diff --git a/src/bench/duplicate_inputs.cpp b/src/bench/duplicate_inputs.cpp index 46e0f348e1..656320f4c5 100644 --- a/src/bench/duplicate_inputs.cpp +++ b/src/bench/duplicate_inputs.cpp @@ -39,7 +39,7 @@ static void DuplicateInputs(benchmark::State& state) coinbaseTx.vin[0].prevout.SetNull(); coinbaseTx.vout.resize(1); coinbaseTx.vout[0].scriptPubKey = SCRIPT_PUB; - coinbaseTx.vout[0].nValue = GetBlockSubsidy(nHeight, chainparams.GetConsensus()); + coinbaseTx.vout[0].nValue = GetBlockSubsidy(*pcustomcsview, nHeight, chainparams.GetConsensus()); coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0; diff --git a/src/chain.cpp b/src/chain.cpp index bb867ea87a..e40abf7bd5 100644 --- a/src/chain.cpp +++ b/src/chain.cpp @@ -5,6 +5,9 @@ #include +#include +#include + /** * CChain implementation */ @@ -144,7 +147,7 @@ int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& fr r = from.nChainWork - to.nChainWork; sign = -1; } - r = r * arith_uint256(params.pos.nTargetSpacing) / GetBlockProof(tip); + r = r * arith_uint256(GetTargetSpacing(*pcustomcsview)) / GetBlockProof(tip); if (r.bits() > 63) { return sign * std::numeric_limits::max(); } diff --git a/src/consensus/params.h b/src/consensus/params.h index 17bb5f2343..fa3c58c400 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -146,21 +146,6 @@ struct Params { }; PoS pos; - uint32_t blocksPerDay() const { - static const uint32_t blocks = 60 * 60 * 24 / pos.nTargetSpacing; - return blocks; - } - - uint32_t blocksCollateralizationRatioCalculation() const { - static const uint32_t blocks = 15 * 60 / pos.nTargetSpacing; - return blocks; - } - - uint32_t blocksCollateralAuction() const { - static const uint32_t blocks = 6 * 60 * 60 / pos.nTargetSpacing; - return blocks; - } - /** * Minimum blocks including miner confirmation of the total of 2016 blocks in a retargeting period, * (nTargetTimespan / nTargetSpacing) which is also used for BIP9 deployments. diff --git a/src/dfi/anchors.cpp b/src/dfi/anchors.cpp index de208b0757..627a4398bc 100644 --- a/src/dfi/anchors.cpp +++ b/src/dfi/anchors.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -848,12 +849,14 @@ bool ContextualValidateAnchor(const CAnchorData &anchor, CBlockIndex &anchorBloc return error("%s: Post-fork anchor marker missing or incorrect.", __func__); } + const auto frequency = pcustomcsview->GetAnchorFrequency(); + // Only anchor by specified frequency - if (anchorCreationHeight % Params().GetConsensus().mn.anchoringFrequency != 0) { + if (anchorCreationHeight % frequency != 0) { return error("%s: Anchor height does not meet frequency rule. Height %ld, frequency %d", __func__, anchorCreationHeight, - Params().GetConsensus().mn.anchoringFrequency); + frequency); } // Make sure height exist @@ -883,7 +886,7 @@ bool ContextualValidateAnchor(const CAnchorData &anchor, CBlockIndex &anchorBloc } // Get start anchor height - int anchorHeight = static_cast(anchorCreationHeight) - Params().GetConsensus().mn.anchoringFrequency; + int anchorHeight = static_cast(anchorCreationHeight) - frequency; // Recreate the creation height of the anchor int64_t timeDepth = Params().GetConsensus().mn.anchoringTimeDepth; @@ -900,12 +903,12 @@ bool ContextualValidateAnchor(const CAnchorData &anchor, CBlockIndex &anchorBloc } // Wind back further by anchoring frequency - while (anchorHeight > 0 && anchorHeight % Params().GetConsensus().mn.anchoringFrequency != 0) { + while (anchorHeight > 0 && anchorHeight % frequency != 0) { --anchorHeight; } // Check heights match - if (static_cast(anchor.height) != anchorHeight) { + if (anchor.height != anchorHeight) { return error( "%s: Anchor height mismatch. Anchor height %d calculated height %d", __func__, anchor.height, anchorHeight); } diff --git a/src/dfi/consensus/governance.cpp b/src/dfi/consensus/governance.cpp index ab364f725f..c88ffc4180 100644 --- a/src/dfi/consensus/governance.cpp +++ b/src/dfi/consensus/governance.cpp @@ -48,6 +48,12 @@ Res CGovernanceConsensus::operator()(const CGovernanceMessage &obj) const { if (newExport.empty()) { return Res::Err("Cannot export empty attribute map"); } + + if (height >= static_cast(consensus.DF24Height)) { + if (res = CheckTimeRelatedVars(*newVar); !res) { + return res; + } + } } CDataStructureV0 foundationMembers{AttributeTypes::Param, ParamIDs::Foundation, DFIPKeys::Members}; @@ -165,6 +171,9 @@ Res CGovernanceConsensus::operator()(const CGovernanceUnsetHeightMessage &obj) c if (auto res = authCheck.CanSetGov(keys); !res) { return res; } + if (auto res = CheckTimeRelatedVars(keys); !res) { + return res; + } } auto var = mnview.GetVariable(name); @@ -266,6 +275,12 @@ Res CGovernanceConsensus::operator()(const CGovernanceHeightMessage &obj) const if (res = authCheck.CanSetGov(*newVar); !res) { return res; } + + if (height >= static_cast(consensus.DF24Height)) { + if (res = CheckTimeRelatedVars(*newVar); !res) { + return res; + } + } } auto storedGovVars = mnview.GetStoredVariablesRange(height, obj.startHeight); diff --git a/src/dfi/consensus/icxorders.cpp b/src/dfi/consensus/icxorders.cpp index 503c43ed13..338dd17983 100644 --- a/src/dfi/consensus/icxorders.cpp +++ b/src/dfi/consensus/icxorders.cpp @@ -129,8 +129,12 @@ Res CICXOrdersConsensus::operator()(const CICXMakeOfferMessage &obj) const { return Res::Err("order with creation tx " + makeoffer.orderTx.GetHex() + " does not exists!"); } - auto expiry = static_cast(height) < consensus.DF10EunosPayaHeight ? CICXMakeOffer::DEFAULT_EXPIRY - : CICXMakeOffer::EUNOSPAYA_DEFAULT_EXPIRY; + const auto attributes = mnview.GetAttributes(); + const CDataStructureV0 key{AttributeTypes::Param, ParamIDs::ICX, DFIPKeys::OfferDefaultExpiry}; + const auto defaultExpiry = attributes->GetValue(key, CICXMakeOffer::EUNOSPAYA_DEFAULT_EXPIRY); + + auto expiry = + static_cast(height) < consensus.DF10EunosPayaHeight ? CICXMakeOffer::DEFAULT_EXPIRY : defaultExpiry; if (makeoffer.expiry < expiry) { return Res::Err("offer expiry must be greater than %d!", expiry - 1); @@ -198,6 +202,8 @@ Res CICXOrdersConsensus::operator()(const CICXSubmitDFCHTLCMessage &obj) const { return Res::Err("dfc htlc already submitted!"); } + const auto attributes = mnview.GetAttributes(); + CScript srcAddr; if (order->orderType == CICXOrder::TYPE_INTERNAL) { // check auth @@ -212,7 +218,8 @@ Res CICXOrdersConsensus::operator()(const CICXSubmitDFCHTLCMessage &obj) const { if (static_cast(height) < consensus.DF10EunosPayaHeight) { timeout = CICXSubmitDFCHTLC::MINIMUM_TIMEOUT; } else { - timeout = CICXSubmitDFCHTLC::EUNOSPAYA_MINIMUM_TIMEOUT; + const CDataStructureV0 key{AttributeTypes::Param, ParamIDs::ICX, DFIPKeys::SubmitMinTimeout}; + timeout = attributes->GetValue(key, CICXSubmitDFCHTLC::EUNOSPAYA_MINIMUM_TIMEOUT); } if (submitdfchtlc.timeout < timeout) { @@ -297,7 +304,8 @@ Res CICXOrdersConsensus::operator()(const CICXSubmitDFCHTLCMessage &obj) const { timeout = CICXSubmitDFCHTLC::MINIMUM_2ND_TIMEOUT; btcBlocksInDfi = CICXSubmitEXTHTLC::BTC_BLOCKS_IN_DFI_BLOCKS; } else { - timeout = CICXSubmitDFCHTLC::EUNOSPAYA_MINIMUM_2ND_TIMEOUT; + const CDataStructureV0 key{AttributeTypes::Param, ParamIDs::ICX, DFIPKeys::SubmitMin2ndTimeout}; + timeout = attributes->GetValue(key, CICXSubmitDFCHTLC::EUNOSPAYA_MINIMUM_2ND_TIMEOUT); btcBlocksInDfi = CICXSubmitEXTHTLC::BTC_BLOCKS_IN_DFI_BLOCKS; } @@ -382,7 +390,9 @@ Res CICXOrdersConsensus::operator()(const CICXSubmitEXTHTLCMessage &obj) const { btcBlocksInDfi = CICXSubmitEXTHTLC::BTC_BLOCKS_IN_DFI_BLOCKS; } else { timeout = CICXSubmitEXTHTLC::EUNOSPAYA_MINIMUM_2ND_TIMEOUT; - btcBlocksInDfi = CICXSubmitEXTHTLC::EUNOSPAYA_BTC_BLOCKS_IN_DFI_BLOCKS; + const auto attributes = mnview.GetAttributes(); + const CDataStructureV0 key{AttributeTypes::Param, ParamIDs::ICX, DFIPKeys::SubmitBTCBlocksInDFI}; + btcBlocksInDfi = attributes->GetValue(key, CICXSubmitEXTHTLC::EUNOSPAYA_BTC_BLOCKS_IN_DFI_BLOCKS); } if (submitexthtlc.timeout < timeout) { diff --git a/src/dfi/consensus/masternodes.cpp b/src/dfi/consensus/masternodes.cpp index 0c08d1db70..56e1e4dc8a 100644 --- a/src/dfi/consensus/masternodes.cpp +++ b/src/dfi/consensus/masternodes.cpp @@ -15,7 +15,7 @@ Res CMasternodesConsensus::CheckMasternodeCreationTx() const { const auto height = txCtx.GetHeight(); const auto &tx = txCtx.GetTransaction(); - if (tx.vout.size() < 2 || tx.vout[0].nValue < GetMnCreationFee(height) || tx.vout[0].nTokenId != DCT_ID{0} || + if (tx.vout.size() < 2 || tx.vout[0].nValue < GetMnCreationFee() || tx.vout[0].nTokenId != DCT_ID{0} || tx.vout[1].nValue != GetMnCollateralAmount(height) || tx.vout[1].nTokenId != DCT_ID{0}) { return Res::Err("malformed tx vouts (wrong creation fee or collateral amount)"); } diff --git a/src/dfi/consensus/txvisitor.cpp b/src/dfi/consensus/txvisitor.cpp index 4b032ef39d..2b44a906e5 100644 --- a/src/dfi/consensus/txvisitor.cpp +++ b/src/dfi/consensus/txvisitor.cpp @@ -199,6 +199,82 @@ Res AuthManager::CanSetGov(const ATTRIBUTES &var) { return Res::Ok(); } +static Res CheckTimeRelatedVarsInternal(const std::set &pendingKeys) { + std::set checkingKeys; + checkingKeys.insert(CDataStructureV0{AttributeTypes::Param, ParamIDs::BlockTime, DFIPKeys::EmissionReduction}); + checkingKeys.insert(CDataStructureV0{AttributeTypes::Param, ParamIDs::BlockTime, DFIPKeys::TargetSpacing}); + checkingKeys.insert(CDataStructureV0{AttributeTypes::Param, ParamIDs::BlockTime, DFIPKeys::TargetTimespan}); + checkingKeys.insert(CDataStructureV0{AttributeTypes::Param, ParamIDs::Anchors, DFIPKeys::Frequency}); + checkingKeys.insert(CDataStructureV0{AttributeTypes::Param, ParamIDs::Anchors, DFIPKeys::TeamChange}); + checkingKeys.insert(CDataStructureV0{AttributeTypes::Param, ParamIDs::Masternodes, DFIPKeys::ActivationDelay}); + checkingKeys.insert(CDataStructureV0{AttributeTypes::Param, ParamIDs::Masternodes, DFIPKeys::ResignDelay}); + checkingKeys.insert(CDataStructureV0{AttributeTypes::Param, ParamIDs::ICX, DFIPKeys::OrderDefaultExpiry}); + checkingKeys.insert(CDataStructureV0{AttributeTypes::Param, ParamIDs::ICX, DFIPKeys::OfferDefaultExpiry}); + checkingKeys.insert(CDataStructureV0{AttributeTypes::Param, ParamIDs::ICX, DFIPKeys::OfferRefundTimeout}); + checkingKeys.insert(CDataStructureV0{AttributeTypes::Param, ParamIDs::ICX, DFIPKeys::SubmitMinTimeout}); + checkingKeys.insert(CDataStructureV0{AttributeTypes::Param, ParamIDs::ICX, DFIPKeys::SubmitMin2ndTimeout}); + checkingKeys.insert(CDataStructureV0{AttributeTypes::Param, ParamIDs::ICX, DFIPKeys::SubmitBTCBlocksInDFI}); + + std::set intersection; + for (const auto &key : checkingKeys) { + if (pendingKeys.find(key) != pendingKeys.end()) { + intersection.insert(key); + } + } + + if (intersection.empty() || intersection == checkingKeys) { + return Res::Ok(); + } + + return Res::Err( + "Param Time vars must be changed together. BlockTime: EmissionReduction, TargetSpacing, TargetTimespan. " + "Anchors: Frequency, TeamChange. Masternodes: ActivationDelay, ResignDelay. ICX: OrderDefaultExpiry, " + "OfferDefaultExpiry, OfferRefundTimeout, SubmitMinTimeout, SubmitMin2ndTimeout, SubmitBTCBlocksInDFI"); +} + +Res CheckTimeRelatedVars(const ATTRIBUTES &var) { + std::set pendingKeys; + var.ForEach( + [&](const CDataStructureV0 &attr, const CAttributeValue &) { + if (attr.type != AttributeTypes::Param) { + return false; + } + pendingKeys.insert(attr); + return true; + }, + CDataStructureV0{AttributeTypes::Param}); + + if (const auto res = CheckTimeRelatedVarsInternal(pendingKeys); !res) { + return res; + } + return Res::Ok(); +} + +Res CheckTimeRelatedVars(const std::vector &keys) { + if (keys.empty()) { + return Res::Err("No keys to check"); + } + std::set pendingKeys; + for (const auto &key : keys) { + const auto res = ATTRIBUTES::ProcessVariable(key, std::nullopt, [&](const auto &attribute, const auto &) { + const auto attr = std::get_if(&attribute); + if (!attr) { + return Res::Err("Attribute type check failed"); + } + pendingKeys.insert(*attr); + return Res::Ok(); + }); + if (!res) { + return res; + } + } + + if (const auto res = CheckTimeRelatedVarsInternal(pendingKeys); !res) { + return res; + } + return Res::Ok(); +} + Res AuthManager::HasGovOrFoundationAuth() { if (HasFoundationAuth() || HasGovernanceAuth()) { return Res::Ok(); diff --git a/src/dfi/consensus/txvisitor.h b/src/dfi/consensus/txvisitor.h index 2039cec57b..1835ecc2de 100644 --- a/src/dfi/consensus/txvisitor.h +++ b/src/dfi/consensus/txvisitor.h @@ -49,6 +49,8 @@ Res HasAuth(const CTransaction &tx, AuthStrategy strategy = AuthStrategy::DirectPubKeyMatch, AuthFlags::Type flags = AuthFlags::None); Res GetERC55AddressFromAuth(const CTransaction &tx, const CCoinsViewCache &coins, CScript &script); +Res CheckTimeRelatedVars(const std::vector &keys); +Res CheckTimeRelatedVars(const ATTRIBUTES &var); class CCustomTxVisitor { protected: diff --git a/src/dfi/errors.h b/src/dfi/errors.h index 6e3e33bf1a..1985e8c0f8 100644 --- a/src/dfi/errors.h +++ b/src/dfi/errors.h @@ -242,6 +242,22 @@ class DeFiErrors { return Res::Err("Unsupported key for Rules {%d}", type); } + static Res GovVarVariableUnsupportedBlockTimeType(const unsigned char type) { + return Res::Err("Unsupported key for BlockTime {%d}", type); + } + + static Res GovVarVariableUnsupportedAnchorType(const unsigned char type) { + return Res::Err("Unsupported key for Anchor {%d}", type); + } + + static Res GovVarVariableUnsupportedICXType(const unsigned char type) { + return Res::Err("Unsupported key for ICX {%d}", type); + } + + static Res GovVarVariableUnsupportedMasternodeType(const unsigned char type) { + return Res::Err("Unsupported key for Masternode {%d}", type); + } + static Res GovVarVariableUnsupportedParamType() { return Res::Err("Unsupported Param ID"); } static Res GovVarVariableUnsupportedGovType() { return Res::Err("Unsupported Governance ID"); } diff --git a/src/dfi/govvariables/attributes.cpp b/src/dfi/govvariables/attributes.cpp index 88992b7343..9377c88699 100644 --- a/src/dfi/govvariables/attributes.cpp +++ b/src/dfi/govvariables/attributes.cpp @@ -108,6 +108,10 @@ const std::map &ATTRIBUTES::allowedParamIDs() { {"foundation", ParamIDs::Foundation }, {"governance", ParamIDs::GovernanceParam}, {"dtoken_restart", ParamIDs::dTokenRestart }, + {"block_time", ParamIDs::BlockTime }, + {"anchors", ParamIDs::Anchors }, + {"masternodes", ParamIDs::Masternodes }, + {"icx", ParamIDs::ICX }, }; return params; } @@ -123,6 +127,10 @@ const std::map &ATTRIBUTES::allowedExportParamsIDs() { {ParamIDs::Foundation, "foundation" }, {ParamIDs::GovernanceParam, "governance" }, {ParamIDs::dTokenRestart, "dtoken_restart"}, + {ParamIDs::BlockTime, "block_time" }, + {ParamIDs::Anchors, "anchors" }, + {ParamIDs::Masternodes, "masternodes" }, + {ParamIDs::ICX, "icx" }, }; return params; } @@ -291,6 +299,19 @@ const std::map> &ATTRIBUTES::allowedKeys {"governance", DFIPKeys::CommunityGovernance}, {"ascending_block_time", DFIPKeys::AscendingBlockTime}, {"govheight_min_blocks", DFIPKeys::GovHeightMinBlocks}, + {"emission_reduction", DFIPKeys::EmissionReduction}, + {"target_spacing", DFIPKeys::TargetSpacing}, + {"target_timespan", DFIPKeys::TargetTimespan}, + {"frequency", DFIPKeys::Frequency}, + {"team_change", DFIPKeys::TeamChange}, + {"activation_delay", DFIPKeys::ActivationDelay}, + {"resign_delay", DFIPKeys::ResignDelay}, + {"order_default_expiry", DFIPKeys::OrderDefaultExpiry}, + {"offer_default_expiry", DFIPKeys::OfferDefaultExpiry}, + {"offer_refund_timeout", DFIPKeys::OfferRefundTimeout}, + {"submit_min_timeout", DFIPKeys::SubmitMinTimeout}, + {"submit_min_2nd_timeout", DFIPKeys::SubmitMin2ndTimeout}, + {"btc_blocks_in_dfi", DFIPKeys::SubmitBTCBlocksInDFI}, }}, {AttributeTypes::EVMType, { @@ -400,6 +421,19 @@ const std::map> &ATTRIBUTES::displayKeys {DFIPKeys::CommunityGovernance, "governance"}, {DFIPKeys::AscendingBlockTime, "ascending_block_time"}, {DFIPKeys::GovHeightMinBlocks, "govheight_min_blocks"}, + {DFIPKeys::EmissionReduction, "emission_reduction"}, + {DFIPKeys::TargetSpacing, "target_spacing"}, + {DFIPKeys::TargetTimespan, "target_timespan"}, + {DFIPKeys::Frequency, "frequency"}, + {DFIPKeys::TeamChange, "team_change"}, + {DFIPKeys::ActivationDelay, "activation_delay"}, + {DFIPKeys::ResignDelay, "resign_delay"}, + {DFIPKeys::OrderDefaultExpiry, "order_default_expiry"}, + {DFIPKeys::OfferDefaultExpiry, "offer_default_expiry"}, + {DFIPKeys::OfferRefundTimeout, "offer_refund_timeout"}, + {DFIPKeys::SubmitMinTimeout, "submit_min_timeout"}, + {DFIPKeys::SubmitMin2ndTimeout, "submit_min_2nd_timeout"}, + {DFIPKeys::SubmitBTCBlocksInDFI, "btc_blocks_in_dfi"}, }}, {AttributeTypes::EVMType, { @@ -505,6 +539,18 @@ static ResVal VerifyUInt64(const std::string &str) { return {x, Res::Ok()}; } +static ResVal VerifyMoreThenZeroUInt32(const std::string &str) { + auto resVal = VerifyUInt32(str); + if (!resVal) { + return resVal; + } + const auto value = std::get(*resVal.val); + if (value == 0) { + return DeFiErrors::GovVarVerifyFactor(); + } + return resVal; +} + static ResVal VerifyMoreThenZeroUInt64(const std::string &str) { auto resVal = VerifyUInt64(str); if (!resVal) { @@ -835,6 +881,19 @@ const std::map( {DFIPKeys::CommunityGovernance, VerifyBool}, {DFIPKeys::AscendingBlockTime, VerifyBool}, {DFIPKeys::GovHeightMinBlocks, VerifyMoreThenZeroUInt64}, + {DFIPKeys::EmissionReduction, VerifyMoreThenZeroUInt32}, + {DFIPKeys::TargetSpacing, VerifyMoreThenZeroInt64}, + {DFIPKeys::TargetTimespan, VerifyMoreThenZeroInt64}, + {DFIPKeys::Frequency, VerifyMoreThenZeroInt64}, + {DFIPKeys::TeamChange, VerifyMoreThenZeroInt64}, + {DFIPKeys::ActivationDelay, VerifyMoreThenZeroInt64}, + {DFIPKeys::ResignDelay, VerifyMoreThenZeroInt64}, + {DFIPKeys::OrderDefaultExpiry, VerifyMoreThenZeroUInt32}, + {DFIPKeys::OfferDefaultExpiry, VerifyMoreThenZeroUInt32}, + {DFIPKeys::OfferRefundTimeout, VerifyMoreThenZeroUInt32}, + {DFIPKeys::SubmitMinTimeout, VerifyMoreThenZeroUInt32}, + {DFIPKeys::SubmitMin2ndTimeout, VerifyMoreThenZeroUInt32}, + {DFIPKeys::SubmitBTCBlocksInDFI, VerifyMoreThenZeroUInt32}, }}, {AttributeTypes::Locks, { @@ -1021,6 +1080,25 @@ static Res CheckValidAttrV0Key(const uint8_t type, const uint32_t typeId, const if (typeKey != DFIPKeys::Members && typeKey != DFIPKeys::GovHeightMinBlocks) { return DeFiErrors::GovVarVariableUnsupportedFoundationType(typeKey); } + } else if (typeId == ParamIDs::BlockTime) { + if (typeKey != DFIPKeys::EmissionReduction && typeKey != DFIPKeys::TargetSpacing && + typeKey != DFIPKeys::TargetTimespan) { + return DeFiErrors::GovVarVariableUnsupportedBlockTimeType(typeKey); + } + } else if (typeId == ParamIDs::Anchors) { + if (typeKey != DFIPKeys::Frequency && typeKey != DFIPKeys::TeamChange) { + return DeFiErrors::GovVarVariableUnsupportedAnchorType(typeKey); + } + } else if (typeId == ParamIDs::Masternodes) { + if (typeKey != DFIPKeys::ActivationDelay && typeKey != DFIPKeys::ResignDelay) { + return DeFiErrors::GovVarVariableUnsupportedMasternodeType(typeKey); + } + } else if (typeId == ParamIDs::ICX) { + if (typeKey != DFIPKeys::OrderDefaultExpiry && typeKey != DFIPKeys::OfferDefaultExpiry && + typeKey != DFIPKeys::OfferRefundTimeout && typeKey != DFIPKeys::SubmitMinTimeout && + typeKey != DFIPKeys::SubmitMin2ndTimeout && typeKey != DFIPKeys::SubmitBTCBlocksInDFI) { + return DeFiErrors::GovVarVariableUnsupportedICXType(typeKey); + } } else if (typeId != ParamIDs::dTokenRestart) { return DeFiErrors::GovVarVariableUnsupportedParamType(); } @@ -1733,9 +1811,14 @@ UniValue ATTRIBUTES::ExportFiltered(GovVarsFilter filter, const std::string &pre } else if (const auto amount = std::get_if(&attribute.second)) { if (attrV0->type == AttributeTypes::Param && (attrV0->typeId == ParamIDs::DFIP2203 || attrV0->typeId == ParamIDs::DFIP2206F || - attrV0->typeId == ParamIDs::DFIP2211F || attrV0->typeId == ParamIDs::dTokenRestart) && + attrV0->typeId == ParamIDs::DFIP2211F || attrV0->typeId == ParamIDs::dTokenRestart || + attrV0->typeId == ParamIDs::BlockTime || attrV0->typeId == ParamIDs::Anchors || + attrV0->typeId == ParamIDs::Masternodes) && (attrV0->key == DFIPKeys::BlockPeriod || attrV0->key == DFIPKeys::StartBlock || - attrV0->key == DFIPKeys::LiquidityCalcSamplingPeriod)) { + attrV0->key == DFIPKeys::LiquidityCalcSamplingPeriod || attrV0->key == DFIPKeys::TargetSpacing || + attrV0->key == DFIPKeys::TargetTimespan || attrV0->key == DFIPKeys::Frequency || + attrV0->key == DFIPKeys::TeamChange || attrV0->key == DFIPKeys::ActivationDelay || + attrV0->key == DFIPKeys::ResignDelay)) { ret.pushKV(key, KeyBuilder(*amount)); } else { const auto decimalStr = GetDecimalStringNormalized(*amount); @@ -2128,7 +2211,7 @@ Res ATTRIBUTES::Validate(const CCustomCSView &view) const { } else if (attrV0->key == DFIPKeys::CommunityGovernance || attrV0->key == DFIPKeys::AscendingBlockTime) { if (view.GetLastHeight() < Params().GetConsensus().DF24Height) { - return Res::Err("Cannot be set before DF24Height"); + return DeFiErrors::GovVarValidateDF24Height(); } } } else if (attrV0->typeId == ParamIDs::Foundation) { @@ -2164,9 +2247,11 @@ Res ATTRIBUTES::Validate(const CCustomCSView &view) const { return DeFiErrors::GovVarValidateBlockPeriod(); } } - } else if (attrV0->typeId == ParamIDs::GovernanceParam) { + } else if (attrV0->typeId == ParamIDs::BlockTime || attrV0->typeId == ParamIDs::GovernanceParam || + attrV0->typeId == ParamIDs::Anchors || attrV0->typeId == ParamIDs::Masternodes || + attrV0->typeId == ParamIDs::ICX) { if (view.GetLastHeight() < Params().GetConsensus().DF24Height) { - return Res::Err("Cannot be set before DF24Height"); + return DeFiErrors::GovVarValidateDF24Height(); } } else if (attrV0->typeId == ParamIDs::dTokenRestart) { if (view.GetLastHeight() < Params().GetConsensus().DF24Height) { @@ -2521,7 +2606,7 @@ Res ATTRIBUTES::Apply(CCustomCSView &mnview, const uint32_t height) { return DeFiErrors::GovVarApplyAutoNoToken(split); } - const auto startHeight = attrV0->key - Params().GetConsensus().blocksPerDay() / 2; + const auto startHeight = attrV0->key - BlocksPerDay(mnview) / 2; if (height < startHeight) { auto var = GovVariable::Create("ATTRIBUTES"); if (!var) { @@ -2611,6 +2696,43 @@ Res ATTRIBUTES::Erase(CCustomCSView &mnview, uint32_t, const std::vectorGetValue(key, Params().GetConsensus().pos.nTargetSpacing); +} + +int64_t GetTargetTimespan(const CCustomCSView &view) { + const auto attributes = view.GetAttributes(); + CDataStructureV0 key{AttributeTypes::Param, ParamIDs::BlockTime, DFIPKeys::TargetTimespan}; + return attributes->GetValue(key, Params().GetConsensus().pos.nTargetTimespanV2); +} + +int64_t DifficultyAdjustment(const CCustomCSView &view) { + return GetTargetTimespan(view) / GetTargetSpacing(view); +} + +int32_t GetEmissionReduction(const CCustomCSView &view) { + const auto attributes = view.GetAttributes(); + CDataStructureV0 key{AttributeTypes::Param, ParamIDs::BlockTime, DFIPKeys::EmissionReduction}; + return attributes->GetValue(key, Params().GetConsensus().emissionReductionPeriod); +} + +uint32_t BlocksPerDay(const CCustomCSView &view) { + uint32_t blocks = 60 * 60 * 24 / GetTargetSpacing(view); + return blocks; +} + +uint32_t BlocksCollateralizationRatioCalculation(const CCustomCSView &view) { + uint32_t blocks = 15 * 60 / GetTargetSpacing(view); + return blocks; +} + +uint32_t BlocksCollateralAuction(const CCustomCSView &view) { + uint32_t blocks = 6 * 60 * 60 / GetTargetSpacing(view); + return blocks; +} + Res GovernanceMemberRemoval(ATTRIBUTES &newVar, ATTRIBUTES &prevVar, const CDataStructureV0 &memberKey, diff --git a/src/dfi/govvariables/attributes.h b/src/dfi/govvariables/attributes.h index 6892acf55f..1b4c911999 100644 --- a/src/dfi/govvariables/attributes.h +++ b/src/dfi/govvariables/attributes.h @@ -46,6 +46,10 @@ enum ParamIDs : uint8_t { DFIP2211F = 'k', GovernanceParam = 'l', dTokenRestart = 'm', + BlockTime = 'n', + Anchors = 'o', + Masternodes = 'p', + ICX = 'q', }; enum OracleIDs : uint8_t { @@ -132,6 +136,19 @@ enum DFIPKeys : uint8_t { AscendingBlockTime = 'A', GovHeightMinBlocks = 'B', CommunityGovernance = 'C', + EmissionReduction = 'D', + TargetSpacing = 'E', + TargetTimespan = 'F', + Frequency = 'G', + TeamChange = 'H', + ActivationDelay = 'I', + ResignDelay = 'J', + OrderDefaultExpiry = 'K', + OfferDefaultExpiry = 'L', + OfferRefundTimeout = 'M', + SubmitMinTimeout = 'N', + SubmitMin2ndTimeout = 'O', + SubmitBTCBlocksInDFI = 'P', }; enum GovernanceKeys : uint8_t { @@ -227,6 +244,10 @@ struct CDataStructureV0 { bool operator<(const CDataStructureV0 &o) const { return std::tie(type, typeId, key, keyId) < std::tie(o.type, o.typeId, o.key, o.keyId); } + + bool operator==(const CDataStructureV0 &other) const { + return (type == other.type && typeId == other.typeId && key == other.key && keyId == other.keyId); + } }; // for future use @@ -414,6 +435,14 @@ Res GovernanceMemberRemoval(ATTRIBUTES &newVar, const CDataStructureV0 &memberKey, const bool canFail = true); +int64_t GetTargetSpacing(const CCustomCSView &view); +int64_t GetTargetTimespan(const CCustomCSView &view); +int64_t DifficultyAdjustment(const CCustomCSView &view); +int32_t GetEmissionReduction(const CCustomCSView &view); +uint32_t BlocksPerDay(const CCustomCSView &view); +uint32_t BlocksCollateralizationRatioCalculation(const CCustomCSView &view); +uint32_t BlocksCollateralAuction(const CCustomCSView &view); + enum GovVarsFilter { All, NoAttributes, diff --git a/src/dfi/icxorder.cpp b/src/dfi/icxorder.cpp index f533dd4338..f8f8bab6d5 100644 --- a/src/dfi/icxorder.cpp +++ b/src/dfi/icxorder.cpp @@ -1,6 +1,8 @@ #include /// ValueFromAmount #include +#include #include +#include #include /// AmountFromValue const uint32_t CICXOrder::DEFAULT_EXPIRY = 2880; @@ -83,8 +85,14 @@ Res CICXOrderView::ICXCreateOrder(const CICXOrderImpl &order) { if (order.orderPrice == 0) { return DeFiErrors::ICXOrderOrderPriceZero(); } - if (order.expiry < CICXOrder::DEFAULT_EXPIRY) { - return DeFiErrors::ICXOrderExiryTooSmall(CICXOrder::DEFAULT_EXPIRY - 1); + + const auto view = static_cast(this); + const auto attributes = view->GetAttributes(); + const CDataStructureV0 expiryKey{AttributeTypes::Param, ParamIDs::ICX, DFIPKeys::OrderDefaultExpiry}; + const auto defaultExpiry = attributes->GetValue(expiryKey, CICXOrder::DEFAULT_EXPIRY); + + if (order.expiry < defaultExpiry) { + return DeFiErrors::ICXOrderExiryTooSmall(defaultExpiry - 1); } OrderKey key(order.idToken, order.creationTx); @@ -243,12 +251,16 @@ Res CICXOrderView::ICXSubmitDFCHTLC(const CICXSubmitDFCHTLCImpl &submitdfchtlc) return DeFiErrors::ICXSubmitTimeout(); } + const auto view = static_cast(this); + const auto attributes = view->GetAttributes(); + const CDataStructureV0 key{AttributeTypes::Param, ParamIDs::ICX, DFIPKeys::OfferRefundTimeout}; + const auto timeout = attributes->GetValue(key, CICXMakeOffer::MAKER_DEPOSIT_REFUND_TIMEOUT); + WriteBy(submitdfchtlc.creationTx, submitdfchtlc); WriteBy(TxidPairKey(submitdfchtlc.offerTx, submitdfchtlc.creationTx), CICXSubmitDFCHTLC::STATUS_OPEN); - WriteBy( - StatusKey(submitdfchtlc.creationHeight + CICXMakeOffer::MAKER_DEPOSIT_REFUND_TIMEOUT, submitdfchtlc.creationTx), - CICXSubmitDFCHTLC::STATUS_EXPIRED); + WriteBy(StatusKey(submitdfchtlc.creationHeight + timeout, submitdfchtlc.creationTx), + CICXSubmitDFCHTLC::STATUS_EXPIRED); WriteBy( StatusKey(submitdfchtlc.creationHeight + submitdfchtlc.timeout, submitdfchtlc.creationTx), CICXSubmitDFCHTLC::STATUS_REFUNDED); @@ -261,8 +273,12 @@ Res CICXOrderView::ICXCloseDFCHTLC(const CICXSubmitDFCHTLCImpl &submitdfchtlc, c EraseBy(TxidPairKey(submitdfchtlc.offerTx, submitdfchtlc.creationTx)); WriteBy(TxidPairKey(submitdfchtlc.offerTx, submitdfchtlc.creationTx), status); - EraseBy(StatusKey( - submitdfchtlc.creationHeight + CICXMakeOffer::MAKER_DEPOSIT_REFUND_TIMEOUT, submitdfchtlc.creationTx)); + const auto view = static_cast(this); + const auto attributes = view->GetAttributes(); + const CDataStructureV0 key{AttributeTypes::Param, ParamIDs::ICX, DFIPKeys::OfferRefundTimeout}; + const auto timeout = attributes->GetValue(key, CICXMakeOffer::MAKER_DEPOSIT_REFUND_TIMEOUT); + + EraseBy(StatusKey(submitdfchtlc.creationHeight + timeout, submitdfchtlc.creationTx)); EraseBy( StatusKey(submitdfchtlc.creationHeight + submitdfchtlc.timeout, submitdfchtlc.creationTx)); @@ -339,21 +355,29 @@ Res CICXOrderView::ICXSubmitEXTHTLC(const CICXSubmitEXTHTLCImpl &submitexthtlc) return DeFiErrors::ICXSubmitTimeout(); } + const auto view = static_cast(this); + const auto attributes = view->GetAttributes(); + const CDataStructureV0 key{AttributeTypes::Param, ParamIDs::ICX, DFIPKeys::OfferRefundTimeout}; + const auto timeout = attributes->GetValue(key, CICXMakeOffer::MAKER_DEPOSIT_REFUND_TIMEOUT); + WriteBy(submitexthtlc.creationTx, submitexthtlc); WriteBy(TxidPairKey(submitexthtlc.offerTx, submitexthtlc.creationTx), CICXSubmitEXTHTLC::STATUS_OPEN); - WriteBy( - StatusKey(submitexthtlc.creationHeight + CICXMakeOffer::MAKER_DEPOSIT_REFUND_TIMEOUT, submitexthtlc.creationTx), - CICXSubmitEXTHTLC::STATUS_EXPIRED); + WriteBy(StatusKey(submitexthtlc.creationHeight + timeout, submitexthtlc.creationTx), + CICXSubmitEXTHTLC::STATUS_EXPIRED); return Res::Ok(); } Res CICXOrderView::ICXCloseEXTHTLC(const CICXSubmitEXTHTLCImpl &submitexthtlc, const uint8_t status) { + const auto view = static_cast(this); + const auto attributes = view->GetAttributes(); + const CDataStructureV0 key{AttributeTypes::Param, ParamIDs::ICX, DFIPKeys::OfferRefundTimeout}; + const auto timeout = attributes->GetValue(key, CICXMakeOffer::MAKER_DEPOSIT_REFUND_TIMEOUT); + WriteBy(submitexthtlc.creationTx, submitexthtlc); EraseBy(TxidPairKey(submitexthtlc.offerTx, submitexthtlc.creationTx)); WriteBy(TxidPairKey(submitexthtlc.offerTx, submitexthtlc.creationTx), status); - EraseBy(StatusKey( - submitexthtlc.creationHeight + CICXMakeOffer::MAKER_DEPOSIT_REFUND_TIMEOUT, submitexthtlc.creationTx)); + EraseBy(StatusKey(submitexthtlc.creationHeight + timeout, submitexthtlc.creationTx)); return Res::Ok(); } diff --git a/src/dfi/loan.cpp b/src/dfi/loan.cpp index 48cc952ace..07299d7966 100644 --- a/src/dfi/loan.cpp +++ b/src/dfi/loan.cpp @@ -197,23 +197,32 @@ std::optional CLoanView::GetInterestRate(const CVaultId &vaultI // Precision 64bit template -inline T InterestPerBlockCalculationV1(CAmount amount, CAmount tokenInterest, CAmount schemeInterest) { +inline T InterestPerBlockCalculationV1(const CCustomCSView &view, + CAmount amount, + CAmount tokenInterest, + CAmount schemeInterest) { const auto netInterest = (tokenInterest + schemeInterest) / 100; // in % - static const auto blocksPerYear = T(365) * Params().GetConsensus().blocksPerDay(); + static const auto blocksPerYear = T(365) * BlocksPerDay(view); return MultiplyAmounts(netInterest, amount) / blocksPerYear; } // Precision 128bit -inline base_uint<128> InterestPerBlockCalculationV2(CAmount amount, CAmount tokenInterest, CAmount schemeInterest) { +inline base_uint<128> InterestPerBlockCalculationV2(const CCustomCSView &view, + CAmount amount, + CAmount tokenInterest, + CAmount schemeInterest) { const auto netInterest = (tokenInterest + schemeInterest) / 100; // in % - static const auto blocksPerYear = 365 * Params().GetConsensus().blocksPerDay(); + static const auto blocksPerYear = 365 * BlocksPerDay(view); return arith_uint256(amount) * netInterest * COIN / blocksPerYear; } // Precision 128bit with negative interest -CInterestAmount InterestPerBlockCalculationV3(CAmount amount, CAmount tokenInterest, CAmount schemeInterest) { +CInterestAmount InterestPerBlockCalculationV3(const CCustomCSView &view, + CAmount amount, + CAmount tokenInterest, + CAmount schemeInterest) { const auto netInterest = (tokenInterest + schemeInterest) / 100; // in % - static const auto blocksPerYear = 365 * Params().GetConsensus().blocksPerDay(); + static const auto blocksPerYear = 365 * BlocksPerDay(view); return {netInterest < 0 && amount > 0, arith_uint256(amount) * std::abs(netInterest) * COIN / blocksPerYear}; } @@ -318,27 +327,28 @@ Res CLoanView::IncreaseInterest(const uint32_t height, rate.interestToHeight = TotalInterestCalculation(rate, height); rate.height = height; + const auto self = *static_cast(this); if (height >= static_cast(Params().GetConsensus().DF18FortCanningGreatWorldHeight)) { CBalances amounts; ReadBy(vaultId, amounts); // Use argument token interest as update from Gov var TX will not be applied to GetLoanTokenByID at this point // in time. - rate.interestPerBlock = InterestPerBlockCalculationV3(amounts.balances[id], tokenInterest, scheme->rate); + rate.interestPerBlock = InterestPerBlockCalculationV3(self, amounts.balances[id], tokenInterest, scheme->rate); } else if (height >= static_cast(Params().GetConsensus().DF14FortCanningHillHeight)) { CBalances amounts; ReadBy(vaultId, amounts); - rate.interestPerBlock = {false, - InterestPerBlockCalculationV2(amounts.balances[id], token->interest, scheme->rate)}; + rate.interestPerBlock = { + false, InterestPerBlockCalculationV2(self, amounts.balances[id], token->interest, scheme->rate)}; } else if (height >= static_cast(Params().GetConsensus().DF12FortCanningMuseumHeight)) { CAmount interestPerBlock = rate.interestPerBlock.amount.GetLow64(); interestPerBlock += - std::ceil(InterestPerBlockCalculationV1(loanIncreased, token->interest, scheme->rate)); + std::ceil(InterestPerBlockCalculationV1(self, loanIncreased, token->interest, scheme->rate)); rate.interestPerBlock = {false, interestPerBlock}; } else { rate.interestPerBlock.amount += - InterestPerBlockCalculationV1(loanIncreased, token->interest, scheme->rate); + InterestPerBlockCalculationV1(self, loanIncreased, token->interest, scheme->rate); } WriteInterestRate(std::make_pair(vaultId, id), rate, height); @@ -384,22 +394,25 @@ Res CLoanView::DecreaseInterest(const uint32_t height, rate.height = height; + const auto self = *static_cast(this); if (height >= static_cast(Params().GetConsensus().DF18FortCanningGreatWorldHeight)) { CBalances amounts; ReadBy(vaultId, amounts); - rate.interestPerBlock = InterestPerBlockCalculationV3(amounts.balances[id], token->interest, scheme->rate); + rate.interestPerBlock = + InterestPerBlockCalculationV3(self, amounts.balances[id], token->interest, scheme->rate); } else if (height >= static_cast(Params().GetConsensus().DF14FortCanningHillHeight)) { CBalances amounts; ReadBy(vaultId, amounts); - rate.interestPerBlock = {false, - InterestPerBlockCalculationV2(amounts.balances[id], token->interest, scheme->rate)}; + rate.interestPerBlock = { + false, InterestPerBlockCalculationV2(self, amounts.balances[id], token->interest, scheme->rate)}; } else if (height >= static_cast(Params().GetConsensus().DF12FortCanningMuseumHeight)) { CAmount interestPerBlock = rate.interestPerBlock.amount.GetLow64(); CAmount newInterestPerBlock = - std::ceil(InterestPerBlockCalculationV1(loanDecreased, token->interest, scheme->rate)); + std::ceil(InterestPerBlockCalculationV1(self, loanDecreased, token->interest, scheme->rate)); rate.interestPerBlock = {false, std::max(CAmount{0}, interestPerBlock - newInterestPerBlock)}; } else { - auto interestPerBlock = InterestPerBlockCalculationV1(loanDecreased, token->interest, scheme->rate); + auto interestPerBlock = + InterestPerBlockCalculationV1(self, loanDecreased, token->interest, scheme->rate); rate.interestPerBlock = rate.interestPerBlock.amount < interestPerBlock ? CInterestAmount{false, 0} : CInterestAmount{false, rate.interestPerBlock.amount - interestPerBlock}; @@ -423,7 +436,10 @@ void CLoanView::ResetInterest(const uint32_t height, ReadBy(vaultId, amounts); const CInterestRateV3 rate{ - height, InterestPerBlockCalculationV3(amounts.balances[id], token->interest, scheme->rate), {false, 0} + height, + InterestPerBlockCalculationV3( + *static_cast(this), amounts.balances[id], token->interest, scheme->rate), + {false, 0} }; WriteInterestRate(std::make_pair(vaultId, id), rate, height); diff --git a/src/dfi/loan.h b/src/dfi/loan.h index 47e60369a3..d43dae6b87 100644 --- a/src/dfi/loan.h +++ b/src/dfi/loan.h @@ -11,6 +11,8 @@ #include #include