From dd2c9f440d5f90b2884f6fa7c9d114b0d51f2265 Mon Sep 17 00:00:00 2001 From: Bushstar Date: Fri, 13 May 2022 11:21:10 +0400 Subject: [PATCH 01/18] Token Lock --- src/chainparams.cpp | 7 +- src/consensus/params.h | 1 + src/init.cpp | 1 + src/masternodes/govvariables/attributes.cpp | 146 +++++--- src/masternodes/govvariables/attributes.h | 7 +- src/masternodes/gv.h | 2 + src/masternodes/loan.cpp | 10 +- src/masternodes/loan.h | 4 +- src/masternodes/masternodes.cpp | 59 +++- src/masternodes/masternodes.h | 6 +- src/masternodes/mn_checks.cpp | 8 + src/masternodes/oracles.cpp | 17 + src/masternodes/oracles.h | 7 + src/masternodes/rpc_loan.cpp | 2 +- src/masternodes/rpc_poolpair.cpp | 5 + src/masternodes/tokens.cpp | 29 -- src/masternodes/tokens.h | 2 +- src/rpc/blockchain.cpp | 1 + test/functional/feature_loan_payback_dfi.py | 2 +- .../functional/feature_loan_payback_dfi_v2.py | 2 +- test/functional/feature_setgov.py | 23 +- test/functional/feature_token_lock.py | 322 ++++++++++++++++++ test/functional/rpc_blockchain.py | 1 + test/functional/test_runner.py | 1 + 24 files changed, 566 insertions(+), 99 deletions(-) create mode 100644 test/functional/feature_token_lock.py diff --git a/src/chainparams.cpp b/src/chainparams.cpp index f653376d16..3a90fb3c46 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -129,7 +129,8 @@ class CMainParams : public CChainParams { consensus.FortCanningMuseumHeight = 1430640; consensus.FortCanningParkHeight = 1503143; consensus.FortCanningHillHeight = 1604999; // Feb 7, 2022. - consensus.FortCanningRoadHeight = 1786000; // April 11, 2022. + consensus.FortCanningRoadHeight = 1786000; // April 11, 2022. + consensus.FortCanningGreenHeight = std::numeric_limits::max(); consensus.pos.diffLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // consensus.pos.nTargetTimespan = 14 * 24 * 60 * 60; // two weeks @@ -358,6 +359,7 @@ class CTestNetParams : public CChainParams { consensus.FortCanningParkHeight = 828800; consensus.FortCanningHillHeight = 828900; consensus.FortCanningRoadHeight = 893700; + consensus.FortCanningGreenHeight = std::numeric_limits::max(); consensus.pos.diffLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // consensus.pos.nTargetTimespan = 14 * 24 * 60 * 60; // two weeks @@ -547,6 +549,7 @@ class CDevNetParams : public CChainParams { consensus.FortCanningParkHeight = std::numeric_limits::max(); consensus.FortCanningHillHeight = std::numeric_limits::max(); consensus.FortCanningRoadHeight = std::numeric_limits::max(); + consensus.FortCanningGreenHeight = std::numeric_limits::max(); consensus.pos.diffLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.pos.nTargetTimespan = 5 * 60; // 5 min == 10 blocks @@ -728,6 +731,7 @@ class CRegTestParams : public CChainParams { consensus.FortCanningParkHeight = 10000000; consensus.FortCanningHillHeight = 10000000; consensus.FortCanningRoadHeight = 10000000; + consensus.FortCanningGreenHeight = 10000000; consensus.pos.diffLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.pos.nTargetTimespan = 14 * 24 * 60 * 60; // two weeks @@ -948,6 +952,7 @@ void CRegTestParams::UpdateActivationParametersFromArgs() UpdateHeightValidation("Fort Canning Park", "-fortcanningparkheight", consensus.FortCanningParkHeight); UpdateHeightValidation("Fort Canning Hill", "-fortcanninghillheight", consensus.FortCanningHillHeight); UpdateHeightValidation("Fort Canning Road", "-fortcanningroadheight", consensus.FortCanningRoadHeight); + UpdateHeightValidation("Fort Canning Green", "-fortcanninggreenheight", consensus.FortCanningGreenHeight); if (gArgs.GetBoolArg("-simulatemainnet", false)) { consensus.pos.nTargetTimespan = 5 * 60; // 5 min == 10 blocks diff --git a/src/consensus/params.h b/src/consensus/params.h index 2d047d9bcd..1523986b72 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -95,6 +95,7 @@ struct Params { int FortCanningParkHeight; int FortCanningHillHeight; int FortCanningRoadHeight; + int FortCanningGreenHeight; /** Foundation share after AMK, normalized to COIN = 100% */ CAmount foundationShareDFIP1; diff --git a/src/init.cpp b/src/init.cpp index 2f775dc02d..843ec06f75 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -476,6 +476,7 @@ void SetupServerArgs() gArgs.AddArg("-fortcanningparkheight", "Fort Canning Park fork activation height (regtest only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS); gArgs.AddArg("-fortcanninghillheight", "Fort Canning Hill fork activation height (regtest only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS); gArgs.AddArg("-fortcanningroadheight", "Fort Canning Road fork activation height (regtest only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS); + gArgs.AddArg("-fortcanninggreenheight", "Fort Canning Green fork activation height (regtest only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS); gArgs.AddArg("-jellyfish_regtest", "Configure the regtest network for jellyfish testing", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::OPTIONS); gArgs.AddArg("-simulatemainnet", "Configure the regtest network to mainnet target timespan and spacing ", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::OPTIONS); #ifdef USE_UPNP diff --git a/src/masternodes/govvariables/attributes.cpp b/src/masternodes/govvariables/attributes.cpp index cbf62b8910..bebb761df9 100644 --- a/src/masternodes/govvariables/attributes.cpp +++ b/src/masternodes/govvariables/attributes.cpp @@ -52,6 +52,7 @@ const std::map& ATTRIBUTES::displayVersions() { const std::map& ATTRIBUTES::allowedTypes() { static const std::map types{ + {"locks", AttributeTypes::Locks}, {"params", AttributeTypes::Param}, {"poolpairs", AttributeTypes::Poolpairs}, {"token", AttributeTypes::Token}, @@ -62,6 +63,7 @@ const std::map& ATTRIBUTES::allowedTypes() { const std::map& ATTRIBUTES::displayTypes() { static const std::map types{ {AttributeTypes::Live, "live"}, + {AttributeTypes::Locks, "locks"}, {AttributeTypes::Param, "params"}, {AttributeTypes::Poolpairs, "poolpairs"}, {AttributeTypes::Token, "token"}, @@ -77,10 +79,18 @@ const std::map& ATTRIBUTES::allowedParamIDs() { return params; } +const std::map& ATTRIBUTES::allowedLocksIDs() { + static const std::map params{ + {"token", ParamIDs::TokenID}, + }; + return params; +} + const std::map& ATTRIBUTES::displayParamsIDs() { static const std::map params{ {ParamIDs::DFIP2201, "dfip2201"}, {ParamIDs::DFIP2203, "dfip2203"}, + {ParamIDs::TokenID, "token"}, {ParamIDs::Economy, "economy"}, }; return params; @@ -231,6 +241,11 @@ const std::mapsecond; uint32_t typeId{0}; - if (type != AttributeTypes::Param) { + if (type == AttributeTypes::Param) { + auto id = allowedParamIDs().find(keys[2]); + if (id == allowedParamIDs().end()) { + return ::ShowError("params", allowedParamIDs()); + } + typeId = id->second; + } else if (type == AttributeTypes::Locks) { + auto id = allowedLocksIDs().find(keys[2]); + if (id == allowedLocksIDs().end()) { + return ::ShowError("locks", allowedLocksIDs()); + } + typeId = id->second; + } else { auto id = VerifyInt32(keys[2]); if (!id) { return std::move(id); } typeId = *id.val; - } else { - auto id = allowedParamIDs().find(keys[2]); - if (id == allowedParamIDs().end()) { - return ::ShowError("param", allowedParamIDs()); - } - typeId = id->second; } - auto ikey = allowedKeys().find(type); - if (ikey == allowedKeys().end()) { - return Res::Err("Unsupported type {%d}", type); - } + uint8_t typeKey; + uint32_t locksKey{0}; + if (type != AttributeTypes::Locks) { + auto ikey = allowedKeys().find(type); + if (ikey == allowedKeys().end()) { + return Res::Err("Unsupported type {%d}", type); + } - itype = ikey->second.find(keys[3]); - if (itype == ikey->second.end()) { - return ::ShowError("key", ikey->second); - } + itype = ikey->second.find(keys[3]); + if (itype == ikey->second.end()) { + return ::ShowError("key", ikey->second); + } - auto typeKey = itype->second; + typeKey = itype->second; - if (type == AttributeTypes::Param) { - if (typeId == ParamIDs::DFIP2201) { - if (typeKey == DFIPKeys::RewardPct || - typeKey == DFIPKeys::BlockPeriod) { - return Res::Err("Unsupported type for DFIP2201 {%d}", typeKey); - } - } else if (typeId == ParamIDs::DFIP2203) { - if (typeKey == DFIPKeys::Premium || - typeKey == DFIPKeys::MinSwap) { - return Res::Err("Unsupported type for DFIP2203 {%d}", typeKey); - } + if (type == AttributeTypes::Param) { + if (typeId == ParamIDs::DFIP2201) { + if (typeKey == DFIPKeys::RewardPct || + typeKey == DFIPKeys::BlockPeriod) { + return Res::Err("Unsupported type for DFIP2201 {%d}", typeKey); + } + } else if (typeId == ParamIDs::DFIP2203) { + if (typeKey == DFIPKeys::Premium || + typeKey == DFIPKeys::MinSwap) { + return Res::Err("Unsupported type for DFIP2203 {%d}", typeKey); + } - if (typeKey == DFIPKeys::BlockPeriod) { - futureBlockUpdated = true; + if (typeKey == DFIPKeys::BlockPeriod) { + futureBlockUpdated = true; + } + } else { + return Res::Err("Unsupported Param ID"); } - } else { - return Res::Err("Unsupported Param ID"); - } - } - - CDataStructureV0 attrV0{type, typeId, typeKey}; - - if (attrV0.IsExtendedSize()) { - if (keys.size() != 5 || keys[4].empty()) { - return Res::Err("Exact 5 keys are required {%d}", keys.size()); } - auto id = VerifyInt32(keys[4]); - if (!id) { - return std::move(id); - } - attrV0.keyId = *id.val; } else { - if (keys.size() != 4) { - return Res::Err("Exact 4 keys are required {%d}", keys.size()); + typeKey = ParamIDs::TokenID; + if (const auto keyValue = VerifyInt32(keys[3])) { + locksKey = *keyValue; } } @@ -360,6 +373,28 @@ Res ATTRIBUTES::ProcessVariable(const std::string& key, const std::string& value if (!attribValue) { return std::move(attribValue); } + + if (type == AttributeTypes::Locks) { + return applyVariable(CDataStructureV0{type, typeId, locksKey}, *attribValue.val); + } + + CDataStructureV0 attrV0{type, typeId, typeKey}; + + if (attrV0.IsExtendedSize()) { + if (keys.size() != 5 || keys[4].empty()) { + return Res::Err("Exact 5 keys are required {%d}", keys.size()); + } + auto id = VerifyInt32(keys[4]); + if (!id) { + return std::move(id); + } + attrV0.keyId = *id.val; + } else { + if (keys.size() != 4) { + return Res::Err("Exact 4 keys are required {%d}", keys.size()); + } + } + return applyVariable(attrV0, *attribValue.val); } } catch (const std::out_of_range&) { @@ -478,13 +513,18 @@ UniValue ATTRIBUTES::Export() const { try { const auto id = attrV0->type == AttributeTypes::Param || attrV0->type == AttributeTypes::Live + || attrV0->type == AttributeTypes::Locks ? displayParamsIDs().at(attrV0->typeId) : KeyBuilder(attrV0->typeId); + const auto keyId = attrV0->type == AttributeTypes::Locks + ? KeyBuilder(attrV0->key) + : displayKeys().at(attrV0->type).at(attrV0->key); + auto key = KeyBuilder(displayVersions().at(VersionTypes::v0), displayTypes().at(attrV0->type), id, - displayKeys().at(attrV0->type).at(attrV0->key)); + keyId); if (attrV0->IsExtendedSize()) { key = KeyBuilder(key, attrV0->keyId); @@ -597,6 +637,18 @@ Res ATTRIBUTES::Validate(const CCustomCSView & view) const case AttributeTypes::Live: break; + case AttributeTypes::Locks: + if (view.GetLastHeight() < Params().GetConsensus().FortCanningGreenHeight) { + return Res::Err("Cannot be set before FortCanningGreen"); + } + if (attrV0->typeId != ParamIDs::TokenID) { + return Res::Err("Unrecognised locks id"); + } + if (!view.GetLoanTokenByID(DCT_ID{attrV0->key}).has_value()) { + return Res::Err("No loan token with id (%d)", attrV0->key); + } + break; + default: return Res::Err("Unrecognised type (%d)", attrV0->type); } diff --git a/src/masternodes/govvariables/attributes.h b/src/masternodes/govvariables/attributes.h index 604b3f2dd2..383af60826 100644 --- a/src/masternodes/govvariables/attributes.h +++ b/src/masternodes/govvariables/attributes.h @@ -18,11 +18,13 @@ enum AttributeTypes : uint8_t { Param = 'a', Token = 't', Poolpairs = 'p', + Locks = 'L', }; enum ParamIDs : uint8_t { DFIP2201 = 'a', DFIP2203 = 'b', + TokenID = 'c', Economy = 'e', }; @@ -60,7 +62,7 @@ enum PoolKeys : uint8_t { struct CDataStructureV0 { uint8_t type; uint32_t typeId; - uint8_t key; + uint32_t key; uint32_t keyId; ADD_SERIALIZE_METHODS; @@ -69,7 +71,7 @@ struct CDataStructureV0 { inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(type); READWRITE(typeId); - READWRITE(key); + READWRITE(VARINT(key)); if (IsExtendedSize()) { READWRITE(keyId); } else { @@ -167,6 +169,7 @@ class ATTRIBUTES : public GovVariable, public AutoRegistrator& allowedVersions(); static const std::map& allowedTypes(); static const std::map& allowedParamIDs(); + static const std::map& allowedLocksIDs(); static const std::map>& allowedKeys(); static const std::map(const std::string&)>>>& parseValue(); diff --git a/src/masternodes/gv.h b/src/masternodes/gv.h index cb8507727d..bc73e29228 100644 --- a/src/masternodes/gv.h +++ b/src/masternodes/gv.h @@ -49,6 +49,8 @@ class CGovView : public virtual CStorageView std::shared_ptr GetAttributes() const; + [[nodiscard]] virtual bool AreTokensLocked(const std::set& tokenIds) const = 0; + struct ByHeightVars { static constexpr uint8_t prefix() { return 'G'; } }; struct ByName { static constexpr uint8_t prefix() { return 'g'; } }; }; diff --git a/src/masternodes/loan.cpp b/src/masternodes/loan.cpp index 0e57152da4..a6a00bf805 100644 --- a/src/masternodes/loan.cpp +++ b/src/masternodes/loan.cpp @@ -55,7 +55,7 @@ std::unique_ptr CLoanView::HasLoanCollat return {}; } -std::unique_ptr CLoanView::GetLoanToken(uint256 const & txid) const +boost::optional CLoanView::GetLoanToken(uint256 const & txid) const { auto id = ReadBy(txid); if (id) @@ -63,14 +63,6 @@ std::unique_ptr CLoanView::GetLoanToken(uint25 return {}; } -std::unique_ptr CLoanView::GetLoanTokenByID(DCT_ID const & id) const -{ - auto loanToken = ReadBy(id); - if (loanToken) - return MakeUnique(*loanToken); - return {}; -} - Res CLoanView::SetLoanToken(CLoanSetLoanTokenImpl const & loanToken, DCT_ID const & id) { //this should not happen, but for sure diff --git a/src/masternodes/loan.h b/src/masternodes/loan.h index 9711d9a549..78cd20914e 100644 --- a/src/masternodes/loan.h +++ b/src/masternodes/loan.h @@ -330,8 +330,8 @@ class CLoanView : public virtual CStorageView { void ForEachLoanCollateralToken(std::function callback, CollateralTokenKey const & start = {DCT_ID{0}, UINT_MAX}); std::unique_ptr HasLoanCollateralToken(CollateralTokenKey const & key); - std::unique_ptr GetLoanToken(uint256 const & txid) const; - std::unique_ptr GetLoanTokenByID(DCT_ID const & id) const; + boost::optional GetLoanToken(uint256 const & txid) const; + [[nodiscard]] virtual boost::optional GetLoanTokenByID(DCT_ID const & id) const = 0; Res SetLoanToken(CLoanSetLoanTokenImpl const & loanToken, DCT_ID const & id); Res UpdateLoanToken(CLoanSetLoanTokenImpl const & loanToken, DCT_ID const & id); void ForEachLoanToken(std::function callback, DCT_ID const & start = {0}); diff --git a/src/masternodes/masternodes.cpp b/src/masternodes/masternodes.cpp index 54d3bfe875..eceb20c1c3 100644 --- a/src/masternodes/masternodes.cpp +++ b/src/masternodes/masternodes.cpp @@ -4,10 +4,12 @@ #include #include +#include #include #include #include +#include #include #include #include