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

gui, staking: Implement facilities for mandatory sidestakes and sidestake GUI #2704

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
aecd15e
Initial skeletons for SideStake class
jamescowens Sep 28, 2023
b8a1393
Add payload and registry machinery for SideStake class
jamescowens Sep 29, 2023
4a8d505
The initial implementation of LoadLocalSideStakesFromConfig()
jamescowens Sep 29, 2023
ea86469
Implement ActiveSideStakeEntries()
jamescowens Sep 30, 2023
66f70b7
Change miner to use ActiveSideStakeEntries()
jamescowens Sep 30, 2023
3a4e946
Wire up the rest of the sidestake contract machinery
jamescowens Oct 1, 2023
0bc173f
Add sidestaking entry status to getstakinginfo.
jamescowens Oct 2, 2023
0b4f5ab
Implement RwSettingsUpdated core signal
jamescowens Oct 2, 2023
772b566
Change operation of fEnableSideStaking flag
jamescowens Oct 2, 2023
fe18cc8
Implement enable sidestaking user checkbox in GUI options.
jamescowens Oct 2, 2023
24ad31c
Adjust size of staking frame in options
jamescowens Oct 2, 2023
24c5d87
Add description field for sidestake.
jamescowens Oct 3, 2023
95ffea9
Split out map for local sidestakes
jamescowens Oct 5, 2023
4da4867
Create skeletons for sidestaketablemodel.h/cpp
jamescowens Oct 5, 2023
c988ce3
Add sidestakingTableWidget to optionsdialog form
jamescowens Oct 5, 2023
09aff4e
Implementation of SideStakeTableModel and sidestakeTableView in options
jamescowens Oct 6, 2023
a1a349b
Add missing logic to pick up descriptions in LoadLocalSideStakesFromC…
jamescowens Oct 6, 2023
1a20fd0
Add icons to sidestake new and edit buttons
jamescowens Oct 6, 2023
19a7ea6
Implementation of EditSideStakeDialog
jamescowens Oct 6, 2023
09d9216
Implement proportional column resizing for SideStakeTableView
jamescowens Oct 12, 2023
68310ef
Implement sidestake description validation
jamescowens Oct 14, 2023
8b5f0cb
Sidestake class cleanup.
jamescowens Oct 21, 2023
e33416a
Add V13 height conditional for sidestake registry in GetLowestRegistr…
jamescowens Oct 31, 2023
2065f76
Changes to separate local and mandatory sidestakes classwise
jamescowens Dec 25, 2023
09d2bf6
Change CBitcoinAddress to CTxDestination in sidestake
jamescowens Dec 25, 2023
1c01201
Add serialization support to CScriptID and CNoDestination
jamescowens Dec 26, 2023
01bb812
Add missing IsV13Enabled guard in sidestake BlockValidate
jamescowens Dec 26, 2023
7f894cf
Implement protocol rule for maximum mandatory sidestake allocation total
jamescowens Dec 28, 2023
dc5fbba
Fix logic to require mandatory sidestaking in miner.cpp
jamescowens Dec 28, 2023
84b90cd
Implement mandatory sidestake output checking in ClaimValidator
jamescowens Dec 28, 2023
96c8189
Limit number of mandatory sidestakes in miner
jamescowens Dec 29, 2023
cf42794
Correct addkey for missing parameter count guard for sidestakes
jamescowens Dec 30, 2023
91a9910
Corrections to miner and validation for mandatory sidestaking
jamescowens Dec 30, 2023
059c20a
Adjust mandatory sidestake validation comments
jamescowens Dec 30, 2023
c984d22
Minor sidestake comment cleanups
jamescowens Jan 1, 2024
a82e9cf
Add missing SideStake specializations for ContractToJson
jamescowens Jan 1, 2024
6181ff5
Correct for segfault in variant access - use get_if non-throw
jamescowens Jan 4, 2024
c60aba5
Flesh out Fraction class
jamescowens Jan 20, 2024
60a6a1a
Add unit tests for Fraction class to util_tests
jamescowens Jan 21, 2024
ce9a376
Modify sidestake code to use new Allocation class instead of double
jamescowens Jan 21, 2024
aeb62a3
Change data input to edit sidestake dialog to Qt::EditRole
jamescowens Jan 22, 2024
c6b2f1d
Initial implementation of sidestake unit tests
jamescowens Jan 23, 2024
55efa35
Changes to validator to deal with ToCAmount truncation of remainder
jamescowens Jan 25, 2024
6f868fa
Change equality to greater than or equal in validator comparison
jamescowens Jan 25, 2024
7badd96
Tweaks to Fraction and Sidestake unit tests
jamescowens Jan 25, 2024
2c21474
Introduce error strings in validator to prevent misleading error mess…
jamescowens Jan 25, 2024
83d3f9e
Change out msb in Fraction class based on testing
jamescowens Jan 28, 2024
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
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ add_library(gridcoin_util STATIC
gridcoin/scraper/scraper.cpp
gridcoin/scraper/scraper_net.cpp
gridcoin/scraper/scraper_registry.cpp
gridcoin/sidestake.cpp
gridcoin/staking/difficulty.cpp
gridcoin/staking/exceptions.cpp
gridcoin/staking/kernel.cpp
Expand Down
2 changes: 2 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ GRIDCOIN_CORE_H = \
gridcoin/scraper/scraper.h \
gridcoin/scraper/scraper_net.h \
gridcoin/scraper/scraper_registry.h \
gridcoin/sidestake.h \
gridcoin/staking/chain_trust.h \
gridcoin/staking/difficulty.h \
gridcoin/staking/exceptions.h \
Expand Down Expand Up @@ -258,6 +259,7 @@ GRIDCOIN_CORE_CPP = addrdb.cpp \
gridcoin/scraper/scraper.cpp \
gridcoin/scraper/scraper_net.cpp \
gridcoin/scraper/scraper_registry.cpp \
gridcoin/sidestake.cpp \
gridcoin/staking/difficulty.cpp \
gridcoin/staking/exceptions.cpp \
gridcoin/staking/kernel.cpp \
Expand Down
7 changes: 7 additions & 0 deletions src/Makefile.qt.include
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ QT_FORMS_UI = \
qt/forms/consolidateunspentwizardsendpage.ui \
qt/forms/diagnosticsdialog.ui \
qt/forms/editaddressdialog.ui \
qt/forms/editsidestakedialog.ui \
qt/forms/favoritespage.ui \
qt/forms/intro.ui \
qt/forms/mrcrequestpage.ui \
Expand Down Expand Up @@ -143,6 +144,7 @@ QT_MOC_CPP = \
qt/moc_csvmodelwriter.cpp \
qt/moc_diagnosticsdialog.cpp \
qt/moc_editaddressdialog.cpp \
qt/moc_editsidestakedialog.cpp \
qt/moc_favoritespage.cpp \
qt/moc_guiutil.cpp \
qt/moc_intro.cpp \
Expand All @@ -161,6 +163,7 @@ QT_MOC_CPP = \
qt/moc_rpcconsole.cpp \
qt/moc_sendcoinsdialog.cpp \
qt/moc_sendcoinsentry.cpp \
qt/moc_sidestaketablemodel.cpp \
qt/moc_signverifymessagedialog.cpp \
qt/moc_trafficgraphwidget.cpp \
qt/moc_transactiondesc.cpp \
Expand Down Expand Up @@ -249,6 +252,7 @@ GRIDCOINRESEARCH_QT_H = \
qt/decoration.h \
qt/diagnosticsdialog.h \
qt/editaddressdialog.h \
qt/editsidestakedialog.h \
qt/favoritespage.h \
qt/guiconstants.h \
qt/guiutil.h \
Expand Down Expand Up @@ -285,6 +289,7 @@ GRIDCOINRESEARCH_QT_H = \
qt/rpcconsole.h \
qt/sendcoinsdialog.h \
qt/sendcoinsentry.h \
qt/sidestaketablemodel.h \
qt/signverifymessagedialog.h \
qt/trafficgraphwidget.h \
qt/transactiondesc.h \
Expand Down Expand Up @@ -340,6 +345,7 @@ GRIDCOINRESEARCH_QT_CPP = \
qt/decoration.cpp \
qt/diagnosticsdialog.cpp \
qt/editaddressdialog.cpp \
qt/editsidestakedialog.cpp \
qt/favoritespage.cpp \
qt/guiutil.cpp \
qt/intro.cpp \
Expand Down Expand Up @@ -372,6 +378,7 @@ GRIDCOINRESEARCH_QT_CPP = \
qt/rpcconsole.cpp \
qt/sendcoinsdialog.cpp \
qt/sendcoinsentry.cpp \
qt/sidestaketablemodel.cpp \
qt/signverifymessagedialog.cpp \
qt/trafficgraphwidget.cpp \
qt/transactiondesc.cpp \
Expand Down
1 change: 1 addition & 0 deletions src/Makefile.test.include
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ GRIDCOIN_TESTS =\
test/gridcoin/protocol_tests.cpp \
test/gridcoin/researcher_tests.cpp \
test/gridcoin/scraper_registry_tests.cpp \
test/gridcoin/sidestake_tests.cpp \
test/gridcoin/superblock_tests.cpp \
test/key_tests.cpp \
test/merkle_tests.cpp \
Expand Down
4 changes: 4 additions & 0 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ class CMainParams : public CChainParams {
consensus.InitialMRCFeeFractionPostZeroInterval = Fraction(2, 5);
// Zero day interval is 14 days on mainnet
consensus.MRCZeroPaymentInterval = 14 * 24 * 60 * 60;
// The maximum ratio of rewards that can be allocated to all of the mandatory sidestakes.
consensus.MaxMandatorySideStakeTotalAlloc = Fraction(1, 4);
// The "standard" contract replay lookback for those contract types
// that do not have a registry db.
consensus.StandardContractReplayLookback = 180 * 24 * 60 * 60;
Expand Down Expand Up @@ -187,6 +189,8 @@ class CTestNetParams : public CChainParams {
consensus.InitialMRCFeeFractionPostZeroInterval = Fraction(2, 5);
// Zero day interval is 10 minutes on testnet. The very short interval facilitates testing.
consensus.MRCZeroPaymentInterval = 10 * 60;
// The maximum ratio of rewards that can be allocated to all of the mandatory sidestakes.
consensus.MaxMandatorySideStakeTotalAlloc = Fraction(1, 4);
// The "standard" contract replay lookback for those contract types
// that do not have a registry db.
consensus.StandardContractReplayLookback = 180 * 24 * 60 * 60;
Expand Down
4 changes: 4 additions & 0 deletions src/consensus/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ struct Params {
* forfeiture of fees to the staker and/or foundation. Only consensus critical at BlockV12Height or above.
*/
int64_t MRCZeroPaymentInterval;
/**
* @brief The maximum allocation (as a Fraction) that can be used by all of the mandatory sidestakes
*/
Fraction MaxMandatorySideStakeTotalAlloc;

int64_t StandardContractReplayLookback;

Expand Down
46 changes: 36 additions & 10 deletions src/gridcoin/contract/contract.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "gridcoin/project.h"
#include "gridcoin/researcher.h"
#include "gridcoin/scraper/scraper_registry.h"
#include "gridcoin/sidestake.h"
#include "gridcoin/support/block_finder.h"
#include "gridcoin/support/xml.h"
#include "gridcoin/tx_message.h"
Expand Down Expand Up @@ -276,6 +277,7 @@ class Dispatcher
case ContractType::SCRAPER: return GetScraperRegistry();
case ContractType::VOTE: return GetPollRegistry();
case ContractType::MRC: return m_mrc_contract_handler;
case ContractType::SIDESTAKE: return GetSideStakeRegistry();
default: return m_unknown_handler;
}
}
Expand Down Expand Up @@ -677,12 +679,13 @@ bool Contract::RequiresMasterKey() const
// beacons by signing them with the original private key:
return m_version == 1 && m_action == ContractAction::REMOVE;

case ContractType::POLL: return m_action == ContractAction::REMOVE;
case ContractType::PROJECT: return true;
case ContractType::PROTOCOL: return true;
case ContractType::SCRAPER: return true;
case ContractType::VOTE: return m_action == ContractAction::REMOVE;
default: return false;
case ContractType::POLL: return m_action == ContractAction::REMOVE;
case ContractType::PROJECT: return true;
case ContractType::PROTOCOL: return true;
case ContractType::SCRAPER: return true;
case ContractType::VOTE: return m_action == ContractAction::REMOVE;
case ContractType::SIDESTAKE: return true;
default: return false;
}
}

Expand All @@ -693,10 +696,23 @@ CAmount Contract::RequiredBurnAmount() const

bool Contract::WellFormed() const
{
return m_version > 0 && m_version <= Contract::CURRENT_VERSION
&& m_type != ContractType::UNKNOWN
&& m_action != ContractAction::UNKNOWN
&& m_body.WellFormed(m_action.Value());
bool result = m_version > 0 && m_version <= Contract::CURRENT_VERSION
&& m_type != ContractType::UNKNOWN
&& m_action != ContractAction::UNKNOWN
&& m_body.WellFormed(m_action.Value());

if (!result) {
LogPrint(BCLog::LogFlags::CONTRACT, "WARN: %s: Contract was not well formed. m_version = %u, m_type = %s, "
"m_action = %s, m_body.Wellformed(m_action.Value()) = %u",
__func__,
m_version,
m_type.ToString(),
m_action.ToString(),
m_body.WellFormed(m_action.Value())
);
}

return result;
}

ContractPayload Contract::SharePayload() const
Expand Down Expand Up @@ -761,6 +777,7 @@ Contract::Type Contract::Type::Parse(std::string input)
if (input == "scraper") return ContractType::SCRAPER;
if (input == "protocol") return ContractType::PROTOCOL;
if (input == "message") return ContractType::MESSAGE;
if (input == "sidestake") return ContractType::SIDESTAKE;

return ContractType::UNKNOWN;
}
Expand All @@ -777,6 +794,7 @@ std::string Contract::Type::ToString() const
case ContractType::PROTOCOL: return "protocol";
case ContractType::SCRAPER: return "scraper";
case ContractType::VOTE: return "vote";
case ContractType::SIDESTAKE: return "sidestake";
default: return "";
}
}
Expand All @@ -793,6 +811,7 @@ std::string Contract::Type::ToString(ContractType contract_type)
case ContractType::PROTOCOL: return "protocol";
case ContractType::SCRAPER: return "scraper";
case ContractType::VOTE: return "vote";
case ContractType::SIDESTAKE: return "sidestake";
default: return "";
}
}
Expand All @@ -809,6 +828,7 @@ std::string Contract::Type::ToTranslatedString(ContractType contract_type)
case ContractType::PROTOCOL: return _("protocol");
case ContractType::SCRAPER: return _("scraper");
case ContractType::VOTE: return _("vote");
case ContractType::SIDESTAKE: return _("sidestake");
default: return "";
}
}
Expand Down Expand Up @@ -905,6 +925,9 @@ ContractPayload Contract::Body::ConvertFromLegacy(const ContractType type, uint3
case ContractType::VOTE:
return ContractPayload::Make<LegacyVote>(
LegacyVote::Parse(legacy.m_key, legacy.m_value));
case ContractType::SIDESTAKE:
// Sidestakes have no legacy representation as a contract.
assert(false && "Attempted to convert non-existent legacy sidestake contract.");
case ContractType::OUT_OF_BOUND:
assert(false);
}
Expand Down Expand Up @@ -961,6 +984,9 @@ void Contract::Body::ResetType(const ContractType type)
case ContractType::VOTE:
m_payload.Reset(new Vote());
break;
case ContractType::SIDESTAKE:
m_payload.Reset(new SideStakePayload());
break;
case ContractType::OUT_OF_BOUND:
assert(false);
}
Expand Down
20 changes: 17 additions & 3 deletions src/gridcoin/contract/message.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "amount.h"
#include "gridcoin/contract/message.h"
#include "gridcoin/contract/contract.h"
#include "gridcoin/sidestake.h"
#include "script.h"
#include "wallet/wallet.h"

Expand Down Expand Up @@ -143,24 +144,37 @@ std::string SendContractTx(CWalletTx& wtx_new)

if (balance < COIN || balance < burn_fee + nTransactionFee) {
std::string strError = _("Balance too low to create a contract.");
LogPrintf("%s: %s", __func__, strError);
error("%s: %s", __func__, strError);
return strError;
}

if (!CreateContractTx(wtx_new, reserve_key, burn_fee)) {
std::string strError = _("Error: Transaction creation failed.");
LogPrintf("%s: %s", __func__, strError);
error("%s: %s", __func__, strError);
return strError;
}

for (const auto& pool_tx : mempool.mapTx) {
for (const auto& pool_tx_contract : pool_tx.second.GetContracts()) {
if (pool_tx_contract.m_type == GRC::ContractType::SIDESTAKE) {
std::string strError = _(
"Error: The mandatory sidestake transaction was rejected. "
"There is already a mandatory sidestake transaction in the mempool. "
"Wait until that transaction is bound in a block.");
error("%s: %s", __func__, strError);
return strError;
}
}
}

if (!pwalletMain->CommitTransaction(wtx_new, reserve_key)) {
std::string strError = _(
"Error: The transaction was rejected. This might happen if some of "
"the coins in your wallet were already spent, such as if you used "
"a copy of wallet.dat and coins were spent in the copy but not "
"marked as spent here.");

LogPrintf("%s: %s", __func__, strError);
error("%s: %s", __func__, strError);
return strError;
}

Expand Down
2 changes: 2 additions & 0 deletions src/gridcoin/contract/payload.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ enum class ContractType
SCRAPER, //!< Scraper node authorization grants and revocations.
VOTE, //!< A vote cast by a wallet for a poll.
MRC, //!< A manual rewards claim (MRC) request to pay rewards
SIDESTAKE, //!< Mandatory sidestakes
OUT_OF_BOUND, //!< Marker value for the end of the valid range.
};

Expand All @@ -82,6 +83,7 @@ static constexpr GRC::ContractType CONTRACT_TYPES[] = {
ContractType::SCRAPER,
ContractType::VOTE,
ContractType::MRC,
ContractType::SIDESTAKE,
ContractType::OUT_OF_BOUND
};

Expand Down
2 changes: 2 additions & 0 deletions src/gridcoin/contract/registry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const std::vector<GRC::ContractType> RegistryBookmarks::CONTRACT_TYPES_WITH_REG_
ContractType::PROJECT,
ContractType::PROTOCOL,
ContractType::SCRAPER,
ContractType::SIDESTAKE
};

const std::vector<GRC::ContractType> RegistryBookmarks::CONTRACT_TYPES_SUPPORTING_REVERT = {
Expand All @@ -20,6 +21,7 @@ const std::vector<GRC::ContractType> RegistryBookmarks::CONTRACT_TYPES_SUPPORTIN
ContractType::PROTOCOL,
ContractType::SCRAPER,
ContractType::VOTE,
ContractType::SIDESTAKE
};

} // namespace GRC
18 changes: 17 additions & 1 deletion src/gridcoin/contract/registry.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "gridcoin/beacon.h"
#include "gridcoin/project.h"
#include "gridcoin/protocol.h"
#include "gridcoin/sidestake.h"
#include "gridcoin/scraper/scraper_registry.h"
#include "gridcoin/voting/registry.h"

Expand Down Expand Up @@ -50,6 +51,7 @@ class RegistryBookmarks
case ContractType::PROJECT: return GetWhitelist();
case ContractType::PROTOCOL: return GetProtocolRegistry();
case ContractType::SCRAPER: return GetScraperRegistry();
case ContractType::SIDESTAKE: return GetSideStakeRegistry();
case ContractType::UNKNOWN:
[[fallthrough]];
case ContractType::CLAIM:
Expand Down Expand Up @@ -78,6 +80,7 @@ class RegistryBookmarks
case ContractType::PROTOCOL: return GetProtocolRegistry();
case ContractType::SCRAPER: return GetScraperRegistry();
case ContractType::VOTE: return GetPollRegistry();
case ContractType::SIDESTAKE: return GetSideStakeRegistry();
[[fallthrough]];
case ContractType::UNKNOWN:
[[fallthrough]];
Expand Down Expand Up @@ -154,8 +157,21 @@ class RegistryBookmarks
int lowest_height = std::numeric_limits<int>::max();

for (const auto& iter : m_db_heights) {
int db_height = iter.second;

//! When below the operational range of the sidestake contracts and registry, initialization of the sidestake
//! registry will report zero for height. It is undesirable to return this in the GetLowestRegistryBlockHeight()
//! method, because it will cause the contract replay clamp to go to the Fern mandatory blockheight. Setting
//! the db_height recorded in the bookmarks at V13 height for the sidestake registry for the purpose of contract
//! replay solves the problem.
//!
//! This code can be removed after the V13 mandatory blockheight has been reached.
if (iter.first == GRC::ContractType::SIDESTAKE and db_height < Params().GetConsensus().BlockV13Height) {
db_height = Params().GetConsensus().BlockV13Height;
}

if (iter.second < lowest_height) {
lowest_height = iter.second;
lowest_height = db_height;
}
}

Expand Down
Loading
Loading