diff --git a/.github/workflows/dev-builds.yaml b/.github/workflows/dev-builds.yaml index 3f7e801ffbb..1e07966d75e 100644 --- a/.github/workflows/dev-builds.yaml +++ b/.github/workflows/dev-builds.yaml @@ -8,6 +8,7 @@ on: branches: - master - testnet + - epic/* - t/* - e/* - v* @@ -16,6 +17,7 @@ on: branches: - master - testnet + - epic/* - t/* - e/* - v* diff --git a/.github/workflows/jellyfish-tests.yml b/.github/workflows/jellyfish-tests.yml index 3737f77dff4..8c37b632b83 100644 --- a/.github/workflows/jellyfish-tests.yml +++ b/.github/workflows/jellyfish-tests.yml @@ -2,9 +2,12 @@ name: Jellyfish Tests on: push: - branches: [ master ] + branches: + - epic/* pull_request: - branches: [ master ] + branches: + - master + - epic/* jobs: test: diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 892860a5116..d124f76b2df 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -138,6 +138,7 @@ class CMainParams : public CChainParams { consensus.FortCanningSpringHeight = 2033000; // July 6, 2022. consensus.FortCanningGreatWorldHeight = 2212000; // Sep 7th, 2022. consensus.FortCanningEpilogueHeight = 2257500; // Sep 22nd, 2022. + consensus.GrandCentralHeight = std::numeric_limits<int>::max(); consensus.pos.diffLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // consensus.pos.nTargetTimespan = 14 * 24 * 60 * 60; // two weeks @@ -377,6 +378,7 @@ class CTestNetParams : public CChainParams { consensus.FortCanningSpringHeight = 1086000; consensus.FortCanningGreatWorldHeight = 1223000; consensus.FortCanningEpilogueHeight = 1244000; + consensus.GrandCentralHeight = std::numeric_limits<int>::max(); consensus.pos.diffLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // consensus.pos.nTargetTimespan = 14 * 24 * 60 * 60; // two weeks @@ -571,6 +573,7 @@ class CDevNetParams : public CChainParams { consensus.FortCanningSpringHeight = std::numeric_limits<int>::max(); consensus.FortCanningGreatWorldHeight = std::numeric_limits<int>::max(); consensus.FortCanningEpilogueHeight = std::numeric_limits<int>::max(); + consensus.GrandCentralHeight = std::numeric_limits<int>::max(); consensus.pos.diffLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.pos.nTargetTimespan = 5 * 60; // 5 min == 10 blocks @@ -757,6 +760,7 @@ class CRegTestParams : public CChainParams { consensus.FortCanningSpringHeight = 10000000; consensus.FortCanningGreatWorldHeight = 10000000; consensus.FortCanningEpilogueHeight = 10000000; + consensus.GrandCentralHeight = 10000000; consensus.pos.diffLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.pos.nTargetTimespan = 14 * 24 * 60 * 60; // two weeks @@ -982,6 +986,7 @@ void SetupCommonArgActivationParams(Consensus::Params &consensus) { UpdateHeightValidation("Fort Canning Great World", "-fortcanninggreatworldheight", consensus.FortCanningGreatWorldHeight); UpdateHeightValidation("Fort Canning Great World", "-greatworldheight", consensus.FortCanningGreatWorldHeight); UpdateHeightValidation("Fort Canning Epilogue", "-fortcanningepilogueheight", consensus.FortCanningEpilogueHeight); + UpdateHeightValidation("Grand Central", "-grandcentralheight", consensus.GrandCentralHeight); 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 5586e3edc88..6dca5248508 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -99,6 +99,7 @@ struct Params { int FortCanningSpringHeight; int FortCanningGreatWorldHeight; int FortCanningEpilogueHeight; + int GrandCentralHeight; /** Foundation share after AMK, normalized to COIN = 100% */ CAmount foundationShareDFIP1; diff --git a/src/init.cpp b/src/init.cpp index 93c28e20b04..ecaf89184b4 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -504,7 +504,9 @@ void SetupServerArgs() gArgs.AddArg("-fortcanninggreatworldheight", "Fort Canning Great World fork activation height (regtest only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS); gArgs.AddArg("-greatworldheight", "Alias for Fort Canning Great World fork activation height (regtest only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS); gArgs.AddArg("-fortcanningepilogueheight", "Alias for Fort Canning Epilogue fork activation height (regtest only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS); + gArgs.AddArg("-grandcentralheight", "Grand Central 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("-regtest-skip-loan-collateral-validation", "Skip loan collateral check 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); gArgs.AddArg("-dexstats", strprintf("Enable storing live dex data in DB (default: %u)", DEFAULT_DEXSTATS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); #ifdef USE_UPNP diff --git a/src/masternodes/govvariables/attributes.cpp b/src/masternodes/govvariables/attributes.cpp index c2503d0367a..eab6deb4a2f 100644 --- a/src/masternodes/govvariables/attributes.cpp +++ b/src/masternodes/govvariables/attributes.cpp @@ -82,6 +82,7 @@ const std::map<std::string, uint8_t>& ATTRIBUTES::allowedParamIDs() { // Note: DFIP2206F is currently in beta testing // for testnet. May not be enabled on mainnet until testing is complete. {"dfip2206f", ParamIDs::DFIP2206F}, + {"feature", ParamIDs::Feature}, }; return params; } @@ -103,6 +104,7 @@ const std::map<uint8_t, std::string>& ATTRIBUTES::displayParamsIDs() { {ParamIDs::DFIP2206F, "dfip2206f"}, {ParamIDs::TokenID, "token"}, {ParamIDs::Economy, "economy"}, + {ParamIDs::Feature, "feature"}, }; return params; } @@ -158,6 +160,11 @@ const std::map<uint8_t, std::map<std::string, uint8_t>>& ATTRIBUTES::allowedKeys {"dusd_interest_burn", DFIPKeys::DUSDInterestBurn}, {"dusd_loan_burn", DFIPKeys::DUSDLoanBurn}, {"start_block", DFIPKeys::StartBlock}, + {"gov-unset", DFIPKeys::GovUnset}, + {"gov-foundation", DFIPKeys::GovFoundation}, + {"mn-setrewardaddress", DFIPKeys::MNSetRewardAddress}, + {"mn-setoperatoraddress", DFIPKeys::MNSetOperatorAddress}, + {"mn-setowneraddress", DFIPKeys::MNSetOwnerAddress}, } }, }; @@ -204,6 +211,11 @@ const std::map<uint8_t, std::map<uint8_t, std::string>>& ATTRIBUTES::displayKeys {DFIPKeys::DUSDInterestBurn, "dusd_interest_burn"}, {DFIPKeys::DUSDLoanBurn, "dusd_loan_burn"}, {DFIPKeys::StartBlock, "start_block"}, + {DFIPKeys::GovUnset, "gov-unset"}, + {DFIPKeys::GovFoundation, "gov-foundation"}, + {DFIPKeys::MNSetRewardAddress, "mn-setrewardaddress"}, + {DFIPKeys::MNSetOperatorAddress, "mn-setoperatoraddress"}, + {DFIPKeys::MNSetOwnerAddress, "mn-setowneraddress"}, } }, { @@ -378,6 +390,11 @@ const std::map<uint8_t, std::map<uint8_t, {DFIPKeys::DUSDInterestBurn, VerifyBool}, {DFIPKeys::DUSDLoanBurn, VerifyBool}, {DFIPKeys::StartBlock, VerifyInt64}, + {DFIPKeys::GovUnset, VerifyBool}, + {DFIPKeys::GovFoundation, VerifyBool}, + {DFIPKeys::MNSetRewardAddress, VerifyBool}, + {DFIPKeys::MNSetOperatorAddress, VerifyBool}, + {DFIPKeys::MNSetOwnerAddress, VerifyBool}, } }, { @@ -546,6 +563,14 @@ Res ATTRIBUTES::ProcessVariable(const std::string& key, const std::string& value typeKey != DFIPKeys::DUSDLoanBurn) { return Res::Err("Unsupported type for DFIP2206A {%d}", typeKey); } + } else if (typeId == ParamIDs::Feature) { + if (typeKey != DFIPKeys::GovUnset && + typeKey != DFIPKeys::GovFoundation && + typeKey != DFIPKeys::MNSetRewardAddress && + typeKey != DFIPKeys::MNSetOperatorAddress && + typeKey != DFIPKeys::MNSetOwnerAddress) { + return Res::Err("Unsupported type for Feature {%d}", typeKey); + } } else { return Res::Err("Unsupported Param ID"); } @@ -1052,7 +1077,11 @@ Res ATTRIBUTES::Validate(const CCustomCSView & view) const break; case AttributeTypes::Param: - if (attrV0->typeId == ParamIDs::DFIP2206F || attrV0->key == DFIPKeys::StartBlock || attrV0->typeId == ParamIDs::DFIP2206A) { + if (attrV0->typeId == ParamIDs::Feature) { + if (view.GetLastHeight() < Params().GetConsensus().GrandCentralHeight) { + return Res::Err("Cannot be set before GrandCentralHeight"); + } + } else if (attrV0->typeId == ParamIDs::DFIP2206F || attrV0->key == DFIPKeys::StartBlock || attrV0->typeId == ParamIDs::DFIP2206A) { if (view.GetLastHeight() < Params().GetConsensus().FortCanningSpringHeight) { return Res::Err("Cannot be set before FortCanningSpringHeight"); } @@ -1210,6 +1239,12 @@ Res ATTRIBUTES::Apply(CCustomCSView & mnview, const uint32_t height) } } else if (attrV0->key == TokenKeys::LoanCollateralFactor) { if (height >= static_cast<uint32_t>(Params().GetConsensus().FortCanningEpilogueHeight)) { + // Skip on if skip collateral check is passed + if (Params().NetworkIDString() == CBaseChainParams::REGTEST && + gArgs.GetBoolArg("-regtest-skip-loan-collateral-validation", false)) { + continue; + } + std::set<CAmount> ratio; mnview.ForEachLoanScheme([&ratio](const std::string &identifier, const CLoanSchemeData &data) { ratio.insert(data.ratio); diff --git a/src/masternodes/govvariables/attributes.h b/src/masternodes/govvariables/attributes.h index 2ac5abbc752..03e7fc899a6 100644 --- a/src/masternodes/govvariables/attributes.h +++ b/src/masternodes/govvariables/attributes.h @@ -30,6 +30,7 @@ enum ParamIDs : uint8_t { Economy = 'e', DFIP2206A = 'f', DFIP2206F = 'g', + Feature = 'h', }; enum OracleIDs : uint8_t { @@ -59,6 +60,11 @@ enum DFIPKeys : uint8_t { DUSDInterestBurn = 'g', DUSDLoanBurn = 'h', StartBlock = 'i', + GovUnset = 'j', + GovFoundation = 'k', + MNSetRewardAddress = 'l', + MNSetOperatorAddress = 'm', + MNSetOwnerAddress = 'n', }; enum TokenKeys : uint8_t { diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index 4cab628ea0a..624fa8321de 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -263,6 +263,13 @@ class CCustomMetadataParseVisitor return Res::Ok(); } + Res isPostGrandCentralFork() const { + if(static_cast<int>(height) < consensus.GrandCentralHeight) { + return Res::Err("called before GrandCentral height"); + } + return Res::Ok(); + } + template<typename T> Res serialize(T& obj) const { CDataStream ss(metadata, SER_NETWORK, PROTOCOL_VERSION); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 4712f9b5542..6cb2deafb10 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1336,6 +1336,7 @@ UniValue getblockchaininfo(const JSONRPCRequest& request) BuriedForkDescPushBack(softforks, "fortcanningspring", consensusParams.FortCanningSpringHeight); BuriedForkDescPushBack(softforks, "fortcanninggreatworld", consensusParams.FortCanningGreatWorldHeight); BuriedForkDescPushBack(softforks, "fortcanningepilogue", consensusParams.FortCanningEpilogueHeight); + BuriedForkDescPushBack(softforks, "grandcentral", consensusParams.GrandCentralHeight); BIP9SoftForkDescPushBack(softforks, "testdummy", consensusParams, Consensus::DEPLOYMENT_TESTDUMMY); obj.pushKV("softforks", softforks); diff --git a/test/functional/feature_skip_collateral_factor_check.py b/test/functional/feature_skip_collateral_factor_check.py new file mode 100644 index 00000000000..1c58501a669 --- /dev/null +++ b/test/functional/feature_skip_collateral_factor_check.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2019 The Bitcoin Core developers +# Copyright (c) DeFi Blockchain Developers +# Distributed under the MIT software license, see the accompanying +# file LICENSE or http://www.opensource.org/licenses/mit-license.php. +"""Test - Skip Collateral Factor """ + +from test_framework.test_framework import DefiTestFramework + + +class SkipCollateralFactorTest (DefiTestFramework): + def set_test_params(self): + self.num_nodes = 1 + self.setup_clean_chain = True + self.extra_args = [['-txnotokens=0', '-amkheight=1', '-bayfrontheight=1', '-bayfrontgardensheight=1', '-eunosheight=1', '-txindex=1', '-fortcanningheight=1', '-fortcanningroadheight=1', + '-fortcanninghillheight=1', '-fortcanningcrunchheight=1', '-fortcanninggreatworldheight=1', '-fortcanningepilogueheight=200', '-regtest-skip-loan-collateral-validation', '-jellyfish_regtest=1']] + + def run_test(self): + # Generate chain + self.nodes[0].generate(120) + + # Create loan tokens + self.symbolDUSD = "DUSD" + self.nodes[0].setloantoken({ + 'symbol': self.symbolDUSD, + 'name': self.symbolDUSD, + 'fixedIntervalPriceId': f"{self.symbolDUSD}/USD", + 'mintable': True, + 'interest': -1 + }) + self.nodes[0].generate(1) + + # Store DUSD ID + self.idDUSD = list(self.nodes[0].gettoken(self.symbolDUSD).keys())[0] + + # Move to fork + self.nodes[0].generate(200 - self.nodes[0].getblockcount()) + + # Create loan scheme + self.nodes[0].createloanscheme(150, 1, 'LOAN001') + self.nodes[0].generate(1) + + # Should not throw error + self.nodes[0].setgov( + {"ATTRIBUTES": {f'v0/token/{self.idDUSD}/loan_collateral_factor': '1.50'}}) + + +if __name__ == '__main__': + SkipCollateralFactorTest().main() diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py index e61dc65c984..598d4b45f5e 100755 --- a/test/functional/rpc_blockchain.py +++ b/test/functional/rpc_blockchain.py @@ -140,6 +140,7 @@ def _test_getblockchaininfo(self): 'fortcanningspring': {'type': 'buried', 'active': False, 'height': 10000000}, 'fortcanninggreatworld': {'type': 'buried', 'active': False, 'height': 10000000}, 'fortcanningepilogue': {'type': 'buried', 'active': False, 'height': 10000000}, + 'grandcentral': {'type': 'buried', 'active': False, 'height': 10000000}, 'testdummy': { 'type': 'bip9', 'bip9': { diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index e397fee8b98..79453d6027f 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -244,6 +244,7 @@ 'wallet_listsinceblock.py', 'p2p_leak.py', 'feature_higher_collateral_factor.py', + 'feature_skip_collateral_factor_check.py', 'wallet_encryption.py', 'feature_dersig.py', 'feature_cltv.py',