From 62b6053e87cb1b2a2f6c4cc0e43831da97a6fe36 Mon Sep 17 00:00:00 2001 From: Bushstar <bushsolo@gmail.com> Date: Thu, 13 Jul 2023 10:35:42 +0100 Subject: [PATCH 1/4] Feature gate transferdomain --- src/chainparams.cpp | 1 + src/init.cpp | 1 + src/masternodes/errors.h | 16 ++++ src/masternodes/govvariables/attributes.cpp | 87 +++++++++++++++++---- src/masternodes/govvariables/attributes.h | 13 +++ src/masternodes/mn_checks.cpp | 39 ++++++++- src/masternodes/mn_checks.h | 1 + test/functional/feature_evm.py | 31 +++++++- 8 files changed, 169 insertions(+), 20 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index fb4db3b9ec..6bf772123c 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -1358,6 +1358,7 @@ void SetupCommonArgActivationParams(Consensus::Params &consensus) { UpdateHeightValidation("Changi Intermediate", "-changiintermediateheight", consensus.ChangiIntermediateHeight); UpdateHeightValidation("Changi Intermediate2", "-changiintermediate2height", consensus.ChangiIntermediateHeight2); UpdateHeightValidation("Changi Intermediate3", "-changiintermediate3height", consensus.ChangiIntermediateHeight3); + UpdateHeightValidation("Changi Intermediate4", "-changiintermediate4height", consensus.ChangiIntermediateHeight4); if (gArgs.GetBoolArg("-simulatemainnet", false)) { consensus.pos.nTargetTimespan = 5 * 60; // 5 min == 10 blocks diff --git a/src/init.cpp b/src/init.cpp index 79302546c3..e684b35371 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -518,6 +518,7 @@ void SetupServerArgs() gArgs.AddArg("-changiintermediateheight", "Changi Intermediate fork activation height (regtest only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS); gArgs.AddArg("-changiintermediate2height", "Changi Intermediate2 fork activation height (regtest only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS); gArgs.AddArg("-changiintermediate3height", "Changi Intermediate3 fork activation height (regtest only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS); + gArgs.AddArg("-changiintermediate4height", "Changi Intermediate4 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("-regtest-minttoken-simulate-mainnet", "Simulate mainnet for minttokens on regtest - default behavior on regtest is to allow anyone to mint mintable tokens for ease of testing", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::OPTIONS); diff --git a/src/masternodes/errors.h b/src/masternodes/errors.h index 1c9d1e4cf0..bd26a246bb 100644 --- a/src/masternodes/errors.h +++ b/src/masternodes/errors.h @@ -262,6 +262,10 @@ class DeFiErrors { return Res::Err("Unsupported key for Governance Proposal section - {%d}", type); } + static Res GovVarVariableUnsupportedTransferType(const unsigned char type) { + return Res::Err("Unsupported key for Transfer Domain {%d}", type); + } + static Res GovVarVariableUnsupportedParamType() { return Res::Err("Unsupported Param ID"); } @@ -410,6 +414,10 @@ class DeFiErrors { return Res::Err("tx must have at least one input from account owner"); } + static Res TransferDomainNotEnabled() { + return Res::Err("Cannot create tx, transfer domain is not enabled"); + } + static Res TransferDomainEVMNotEnabled() { return Res::Err("Cannot create tx, EVM is not enabled"); } @@ -426,6 +434,14 @@ class DeFiErrors { return Res::Err("For transferdomain, only DFI token is currently supported"); } + static Res TransferDomainEVMDVMNotEnabled() { + return Res::Err("EVM to DVM is not currently enabled"); + } + + static Res TransferDomainDVMEVMNotEnabled() { + return Res::Err("DVM to EVM is not currently enabled"); + } + static Res TransferDomainETHSourceAddress() { return Res::Err("Src address must be an ETH address in case of \"EVM\" domain"); } diff --git a/src/masternodes/govvariables/attributes.cpp b/src/masternodes/govvariables/attributes.cpp index 325bce1d0e..6aa2269f3b 100644 --- a/src/masternodes/govvariables/attributes.cpp +++ b/src/masternodes/govvariables/attributes.cpp @@ -51,27 +51,29 @@ const std::map<uint8_t, std::string> &ATTRIBUTES::displayVersions() { const std::map<std::string, uint8_t> &ATTRIBUTES::allowedTypes() { static const std::map<std::string, uint8_t> types{ - {"locks", AttributeTypes::Locks }, - {"oracles", AttributeTypes::Oracles }, - {"params", AttributeTypes::Param }, - {"poolpairs", AttributeTypes::Poolpairs }, - {"token", AttributeTypes::Token }, - {"gov", AttributeTypes::Governance}, - {"consortium", AttributeTypes::Consortium}, + {"locks", AttributeTypes::Locks }, + {"oracles", AttributeTypes::Oracles }, + {"params", AttributeTypes::Param }, + {"poolpairs", AttributeTypes::Poolpairs }, + {"token", AttributeTypes::Token }, + {"gov", AttributeTypes::Governance}, + {"consortium", AttributeTypes::Consortium}, + {"transferdomain", AttributeTypes::Transfer }, }; return types; } const std::map<uint8_t, std::string> &ATTRIBUTES::displayTypes() { static const std::map<uint8_t, std::string> types{ - {AttributeTypes::Live, "live" }, - {AttributeTypes::Locks, "locks" }, - {AttributeTypes::Oracles, "oracles" }, - {AttributeTypes::Param, "params" }, - {AttributeTypes::Poolpairs, "poolpairs" }, - {AttributeTypes::Token, "token" }, - {AttributeTypes::Governance, "gov" }, - {AttributeTypes::Consortium, "consortium"}, + {AttributeTypes::Live, "live" }, + {AttributeTypes::Locks, "locks" }, + {AttributeTypes::Oracles, "oracles" }, + {AttributeTypes::Param, "params" }, + {AttributeTypes::Poolpairs, "poolpairs" }, + {AttributeTypes::Token, "token" }, + {AttributeTypes::Governance, "gov" }, + {AttributeTypes::Consortium, "consortium" }, + {AttributeTypes::Transfer, "transferdomain"}, }; return types; } @@ -142,6 +144,20 @@ const std::map<uint8_t, std::string> &ATTRIBUTES::displayGovernanceIDs() { return params; } +const std::map<std::string, uint8_t> &ATTRIBUTES::allowedTransferIDs() { + static const std::map<std::string, uint8_t> params{ + {"edges", TransferIDs::Edges}, + }; + return params; +} + +const std::map<uint8_t, std::string> &ATTRIBUTES::displayTransferIDs() { + static const std::map<uint8_t, std::string> params{ + {TransferIDs::Edges, "edges"}, + }; + return params; +} + const std::map<uint8_t, std::map<std::string, uint8_t>> &ATTRIBUTES::allowedKeys() { static const std::map<uint8_t, std::map<std::string, uint8_t>> keys{ {AttributeTypes::Token, @@ -197,6 +213,7 @@ const std::map<uint8_t, std::map<std::string, uint8_t>> &ATTRIBUTES::allowedKeys {"emission-unused-fund", DFIPKeys::EmissionUnusedFund}, {"mint-tokens-to-address", DFIPKeys::MintTokens}, {"allow-dusd-loops", DFIPKeys::AllowDUSDLoops}, + {"transferdomain", DFIPKeys::TransferDomain}, }}, {AttributeTypes::Governance, { @@ -213,6 +230,11 @@ const std::map<uint8_t, std::map<std::string, uint8_t>> &ATTRIBUTES::allowedKeys {"voting_period", GovernanceKeys::VotingPeriod}, {"cfp_max_cycles", GovernanceKeys::CFPMaxCycles}, }}, + {AttributeTypes::Transfer, + { + {"evm-dvm", TransferKeys::EVM_DVM}, + {"dvm-evm", TransferKeys::DVM_EVM}, + }}, }; return keys; } @@ -275,6 +297,7 @@ const std::map<uint8_t, std::map<uint8_t, std::string>> &ATTRIBUTES::displayKeys {DFIPKeys::EmissionUnusedFund, "emission-unused-fund"}, {DFIPKeys::MintTokens, "mint-tokens-to-address"}, {DFIPKeys::AllowDUSDLoops, "allow-dusd-loops"}, + {DFIPKeys::TransferDomain, "transferdomain"}, }}, {AttributeTypes::Live, { @@ -310,6 +333,11 @@ const std::map<uint8_t, std::map<uint8_t, std::string>> &ATTRIBUTES::displayKeys {GovernanceKeys::VotingPeriod, "voting_period"}, {GovernanceKeys::CFPMaxCycles, "cfp_max_cycles"}, }}, + {AttributeTypes::Transfer, + { + {TransferKeys::EVM_DVM, "evm-dvm"}, + {TransferKeys::DVM_EVM, "dvm-evm"}, + }}, }; return keys; } @@ -604,6 +632,7 @@ const std::map<uint8_t, std::map<uint8_t, std::function<ResVal<CAttributeValue>( {DFIPKeys::EmissionUnusedFund, VerifyBool}, {DFIPKeys::MintTokens, VerifyBool}, {DFIPKeys::AllowDUSDLoops, VerifyBool}, + {DFIPKeys::TransferDomain, VerifyBool}, }}, {AttributeTypes::Locks, { @@ -628,6 +657,11 @@ const std::map<uint8_t, std::map<uint8_t, std::function<ResVal<CAttributeValue>( {GovernanceKeys::VotingPeriod, VerifyUInt32}, {GovernanceKeys::CFPMaxCycles, VerifyUInt32}, }}, + {AttributeTypes::Transfer, + { + {TransferKeys::EVM_DVM, VerifyBool}, + {TransferKeys::DVM_EVM, VerifyBool}, + }}, }; return parsers; } @@ -747,6 +781,12 @@ Res ATTRIBUTES::ProcessVariable(const std::string &key, return DeFiErrors::GovVarVariableInvalidKey("governance", allowedGovernanceIDs()); } typeId = id->second; + } else if (type == AttributeTypes::Transfer) { + auto id = allowedTransferIDs().find(keys[2]); + if (id == allowedTransferIDs().end()) { + return DeFiErrors::GovVarVariableInvalidKey("transferdomain", allowedTransferIDs()); + } + typeId = id->second; } else { auto id = VerifyInt32(keys[2]); if (!id) { @@ -815,7 +855,7 @@ Res ATTRIBUTES::ProcessVariable(const std::string &key, typeKey != DFIPKeys::ConsortiumEnabled && typeKey != DFIPKeys::CFPPayout && typeKey != DFIPKeys::EmissionUnusedFund && typeKey != DFIPKeys::MintTokens && typeKey != DFIPKeys::EVMEnabled && typeKey != DFIPKeys::ICXEnabled && - typeKey != DFIPKeys::AllowDUSDLoops) { + typeKey != DFIPKeys::AllowDUSDLoops && typeKey != DFIPKeys::TransferDomain) { return DeFiErrors::GovVarVariableUnsupportedFeatureType(typeKey); } } else if (typeId == ParamIDs::Foundation) { @@ -837,6 +877,13 @@ Res ATTRIBUTES::ProcessVariable(const std::string &key, } else { return DeFiErrors::GovVarVariableUnsupportedGovType(); } + } else if (type == AttributeTypes::Transfer) { + if (typeId == TransferIDs::Edges) { + if (typeKey != TransferKeys::DVM_EVM && typeKey != TransferKeys::EVM_DVM) + return DeFiErrors::GovVarVariableUnsupportedTransferType(typeKey); + } else { + return DeFiErrors::GovVarVariableUnsupportedGovType(); + } } attrV0 = CDataStructureV0{type, typeId, typeKey}; @@ -1145,6 +1192,8 @@ UniValue ATTRIBUTES::ExportFiltered(GovVarsFilter filter, const std::string &pre id = displayOracleIDs().at(attrV0->typeId); } else if (attrV0->type == AttributeTypes::Governance) { id = displayGovernanceIDs().at(attrV0->typeId); + } else if (attrV0->type == AttributeTypes::Transfer) { + id = displayTransferIDs().at(attrV0->typeId); } else { id = KeyBuilder(attrV0->typeId); } @@ -1556,6 +1605,12 @@ Res ATTRIBUTES::Validate(const CCustomCSView &view) const { } break; + case AttributeTypes::Transfer: + if (view.GetLastHeight() < Params().GetConsensus().NextNetworkUpgradeHeight) { + return Res::Err("Cannot be set before NextNetworkUpgrade"); + } + 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 7a1963767b..973eb925cb 100644 --- a/src/masternodes/govvariables/attributes.h +++ b/src/masternodes/govvariables/attributes.h @@ -23,6 +23,7 @@ enum AttributeTypes : uint8_t { Locks = 'L', Governance = 'g', Consortium = 'c', + Transfer = 'b', }; enum ParamIDs : uint8_t { @@ -46,6 +47,10 @@ enum GovernanceIDs : uint8_t { Proposals = 'b', }; +enum TransferIDs : uint8_t { + Edges = 'a', +}; + enum EconomyKeys : uint8_t { PaybackDFITokens = 'a', PaybackTokens = 'b', @@ -89,6 +94,7 @@ enum DFIPKeys : uint8_t { EVMEnabled = 'u', ICXEnabled = 'v', AllowDUSDLoops = 'w', + TransferDomain = 'x', }; enum GovernanceKeys : uint8_t { @@ -138,6 +144,11 @@ enum PoolKeys : uint8_t { TokenBFeeDir = 'd', }; +enum TransferKeys : uint8_t { + DVM_EVM = 'a', + EVM_DVM = 'b', +}; + struct CDataStructureV0 { uint8_t type; uint32_t typeId; @@ -424,6 +435,7 @@ class ATTRIBUTES : public GovVariable, public AutoRegistrator<GovVariable, ATTRI static const std::map<uint8_t, std::string> &displayOracleIDs(); static const std::map<uint8_t, std::string> &displayConsortiumIDs(); static const std::map<uint8_t, std::string> &displayGovernanceIDs(); + static const std::map<uint8_t, std::string> &displayTransferIDs(); static const std::map<uint8_t, std::map<uint8_t, std::string>> &displayKeys(); Res RefundFuturesContracts(CCustomCSView &mnview, @@ -447,6 +459,7 @@ class ATTRIBUTES : public GovVariable, public AutoRegistrator<GovVariable, ATTRI static const std::map<std::string, uint8_t> &allowedOracleIDs(); static const std::map<std::string, uint8_t> &allowedConsortiumIDs(); static const std::map<std::string, uint8_t> &allowedGovernanceIDs(); + static const std::map<std::string, uint8_t> &allowedTransferIDs(); static const std::map<uint8_t, std::map<std::string, uint8_t>> &allowedKeys(); static const std::map<uint8_t, std::map<uint8_t, std::function<ResVal<CAttributeValue>(const std::string &)>>> &parseValue(); diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index 1b19725ee2..9da7317f08 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -4019,10 +4019,12 @@ static Res ValidateTransferDomainScripts(const CScript &srcScript, const CScript } Res ValidateTransferDomainEdge(const CTransaction &tx, + const CCustomCSView &mnview, uint32_t height, const CCoinsViewCache &coins, const Consensus::Params &consensus, - CTransferDomainItem src, CTransferDomainItem dst) { + CTransferDomainItem src, + CTransferDomainItem dst) { // TODO: Remove code branch on stable. if (height < static_cast<uint32_t>(consensus.ChangiIntermediateHeight3)) { @@ -4039,7 +4041,19 @@ Res ValidateTransferDomainEdge(const CTransaction &tx, if (src.amount.nTokenId != DCT_ID{0} || dst.amount.nTokenId != DCT_ID{0}) return DeFiErrors::TransferDomainIncorrectToken(); + CDataStructureV0 evm_dvm{AttributeTypes::Transfer, TransferIDs::Edges, TransferKeys::EVM_DVM}; + CDataStructureV0 dvm_evm{AttributeTypes::Transfer, TransferIDs::Edges, TransferKeys::DVM_EVM}; + + const auto attributes = mnview.GetAttributes(); + assert(attributes); + if (src.domain == static_cast<uint8_t>(VMDomain::DVM) && dst.domain == static_cast<uint8_t>(VMDomain::EVM)) { + if (height >= static_cast<uint32_t>(consensus.ChangiIntermediateHeight4)) { + if (!attributes->GetValue(dvm_evm, false)) { + return DeFiErrors::TransferDomainDVMEVMNotEnabled(); + } + } + // DVM to EVM auto res = ValidateTransferDomainScripts(src.address, dst.address, VMDomainEdge::DVMToEVM); if (!res) return res; @@ -4047,6 +4061,12 @@ Res ValidateTransferDomainEdge(const CTransaction &tx, return HasAuth(tx, coins, src.address); } else if (src.domain == static_cast<uint8_t>(VMDomain::EVM) && dst.domain == static_cast<uint8_t>(VMDomain::DVM)) { + if (height >= static_cast<uint32_t>(consensus.ChangiIntermediateHeight4)) { + if (!attributes->GetValue(evm_dvm, false)) { + return DeFiErrors::TransferDomainEVMDVMNotEnabled(); + } + } + // EVM to DVM auto res = ValidateTransferDomainScripts(src.address, dst.address, VMDomainEdge::EVMToDVM); if (!res) return res; @@ -4069,6 +4089,10 @@ Res ValidateTransferDomain(const CTransaction &tx, return DeFiErrors::TransferDomainEVMNotEnabled(); } + if (!IsTransferDomainEnabled(height, mnview, consensus)) { + return DeFiErrors::TransferDomainNotEnabled(); + } + if (height >= static_cast<uint32_t>(consensus.ChangiIntermediateHeight4)) { if (obj.transfers.size() < 1) { return DeFiErrors::TransferDomainInvalid(); @@ -4076,7 +4100,7 @@ Res ValidateTransferDomain(const CTransaction &tx, } for (const auto &[src, dst] : obj.transfers) { - auto res = ValidateTransferDomainEdge(tx, height, coins, consensus, src, dst); + auto res = ValidateTransferDomainEdge(tx, mnview, height, coins, consensus, src, dst); if (!res) return res; } @@ -5088,3 +5112,14 @@ bool IsEVMEnabled(const int height, const CCustomCSView &view, const Consensus:: assert(attributes); return attributes->GetValue(enabledKey, false); } + +bool IsTransferDomainEnabled(const int height, const CCustomCSView &view, const Consensus::Params &consensus) { + if (height < consensus.NextNetworkUpgradeHeight) { + return false; + } + + const CDataStructureV0 enabledKey{AttributeTypes::Param, ParamIDs::Feature, DFIPKeys::TransferDomain}; + auto attributes = view.GetAttributes(); + assert(attributes); + return attributes->GetValue(enabledKey, false); +} diff --git a/src/masternodes/mn_checks.h b/src/masternodes/mn_checks.h index 1e59fede46..127629daeb 100644 --- a/src/masternodes/mn_checks.h +++ b/src/masternodes/mn_checks.h @@ -523,6 +523,7 @@ bool IsTestNetwork(); bool IsMainNetwork(); bool IsICXEnabled(const int height, const CCustomCSView &view, const Consensus::Params &consensus); bool IsEVMEnabled(const int height, const CCustomCSView &view, const Consensus::Params &consensus); +bool IsTransferDomainEnabled(const int height, const CCustomCSView &view, const Consensus::Params &consensus); Res HasAuth(const CTransaction &tx, const CCoinsViewCache &coins, const CScript &auth, AuthStrategy strategy = AuthStrategy::DirectPubKeyMatch); Res ValidateTransferDomain(const CTransaction &tx, uint32_t height, diff --git a/test/functional/feature_evm.py b/test/functional/feature_evm.py index 51d2663bf0..4499f65aa4 100755 --- a/test/functional/feature_evm.py +++ b/test/functional/feature_evm.py @@ -21,8 +21,8 @@ def set_test_params(self): self.num_nodes = 2 self.setup_clean_chain = True self.extra_args = [ - ['-txordering=2', '-dummypos=0', '-txnotokens=0', '-amkheight=50', '-bayfrontheight=51', '-eunosheight=80', '-fortcanningheight=82', '-fortcanninghillheight=84', '-fortcanningroadheight=86', '-fortcanningcrunchheight=88', '-fortcanningspringheight=90', '-fortcanninggreatworldheight=94', '-fortcanningepilogueheight=96', '-grandcentralheight=101', '-nextnetworkupgradeheight=105', '-changiintermediateheight=105', '-changiintermediate3height=105', '-subsidytest=1', '-txindex=1'], - ['-txordering=2', '-dummypos=0', '-txnotokens=0', '-amkheight=50', '-bayfrontheight=51', '-eunosheight=80', '-fortcanningheight=82', '-fortcanninghillheight=84', '-fortcanningroadheight=86', '-fortcanningcrunchheight=88', '-fortcanningspringheight=90', '-fortcanninggreatworldheight=94', '-fortcanningepilogueheight=96', '-grandcentralheight=101', '-nextnetworkupgradeheight=105', '-changiintermediateheight=105', '-changiintermediate3height=105', '-subsidytest=1', '-txindex=1'] + ['-txordering=2', '-dummypos=0', '-txnotokens=0', '-amkheight=50', '-bayfrontheight=51', '-eunosheight=80', '-fortcanningheight=82', '-fortcanninghillheight=84', '-fortcanningroadheight=86', '-fortcanningcrunchheight=88', '-fortcanningspringheight=90', '-fortcanninggreatworldheight=94', '-fortcanningepilogueheight=96', '-grandcentralheight=101', '-nextnetworkupgradeheight=105', '-changiintermediateheight=105', '-changiintermediate3height=105', '-changiintermediate4height=105', '-subsidytest=1', '-txindex=1'], + ['-txordering=2', '-dummypos=0', '-txnotokens=0', '-amkheight=50', '-bayfrontheight=51', '-eunosheight=80', '-fortcanningheight=82', '-fortcanninghillheight=84', '-fortcanningroadheight=86', '-fortcanningcrunchheight=88', '-fortcanningspringheight=90', '-fortcanninggreatworldheight=94', '-fortcanningepilogueheight=96', '-grandcentralheight=101', '-nextnetworkupgradeheight=105', '-changiintermediateheight=105', '-changiintermediate3height=105', '-changiintermediate4height=105', '-subsidytest=1', '-txindex=1'] ] def test_tx_without_chainid(self, node, keypair, web3): @@ -86,10 +86,28 @@ def run_test(self): # Move to fork height self.nodes[0].generate(4) + # Check error before EVM enabled + assert_raises_rpc_error(-32600, "Cannot create tx, EVM is not enabled", self.nodes[0].evmtx, eth_address, 0, 21, 21000, to_address, 0.1) + assert_raises_rpc_error(-32600, "Cannot create tx, EVM is not enabled", self.nodes[0].transferdomain, [{"src": {"address":address, "amount":"100@DFI", "domain": 2}, "dst":{"address":eth_address, "amount":"100@DFI", "domain": 3}}]) + # Activate EVM self.nodes[0].setgov({"ATTRIBUTES": {'v0/params/feature/evm': 'true'}}) self.nodes[0].generate(1) + # Check error before transferdomain enabled + assert_raises_rpc_error(-32600, "Cannot create tx, transfer domain is not enabled", self.nodes[0].transferdomain, [{"src": {"address":address, "amount":"100@DFI", "domain": 2}, "dst":{"address":eth_address, "amount":"100@DFI", "domain": 3}}]) + + # Activate transferdomain + self.nodes[0].setgov({"ATTRIBUTES": {'v0/params/feature/transferdomain': 'true'}}) + self.nodes[0].generate(1) + + # Check error before transferdomain DVM to EVM is enabled + assert_raises_rpc_error(-32600, "DVM to EVM is not currently enabled", self.nodes[0].transferdomain, [{"src": {"address":address, "amount":"100@DFI", "domain": 2}, "dst":{"address":eth_address, "amount":"100@DFI", "domain": 3}}]) + + # Activate transferdomain DVM to EVM + self.nodes[0].setgov({"ATTRIBUTES": {'v0/transferdomain/edges/dvm-evm': 'true'}}) + self.nodes[0].generate(1) + # Check transferdomain without DFI balance before DFI address is funded assert_raises_rpc_error(-32600, "amount 0.00000000 is less than 100.00000000", self.nodes[0].transferdomain, [{"src": {"address":address, "amount":"100@DFI", "domain": 2}, "dst":{"address":eth_address, "amount":"100@DFI", "domain": 3}}]) @@ -140,6 +158,15 @@ def run_test(self): assert_raises_rpc_error(-32600, "For transferdomain, only DFI token is currently supported", self.nodes[0].transferdomain, [{"src": {"address":address, "amount":"100@DFI", "domain": 2}, "dst":{"address":eth_address, "amount":"100@BTC", "domain": 3}}]) assert_raises_rpc_error(-32600, "Excess data set, maximum allow is 0", self.nodes[0].transferdomain, [{"src": {"address":address, "amount":"100@DFI", "domain": 2, "data": "1"}, "dst":{"address":eth_address, "amount":"100@DFI", "domain": 3}}]) assert_raises_rpc_error(-32600, "Excess data set, maximum allow is 0", self.nodes[0].transferdomain, [{"src": {"address":address, "amount":"100@DFI", "domain": 2}, "dst":{"address":eth_address, "amount":"100@DFI", "domain": 3, "data": "1"}}]) + + # Check error before transferdomain DVM to EVM is enabled + assert_raises_rpc_error(-32600, "EVM to DVM is not currently enabled", self.nodes[0].transferdomain, [{"src": {"address":address, "amount":"100@DFI", "domain": 3}, "dst":{"address":eth_address, "amount":"100@DFI", "domain": 2}}]) + + # Activate transferdomain DVM to EVM + self.nodes[0].setgov({"ATTRIBUTES": {'v0/transferdomain/edges/evm-dvm': 'true'}}) + self.nodes[0].generate(1) + + # Test not enough balance for EVM to DVM transfer assert_raises_rpc_error(-32600, "Not enough balance in " + eth_address + " to cover \"EVM\" domain transfer", self.nodes[0].transferdomain, [{"src": {"address":eth_address, "amount":"100@DFI", "domain": 3}, "dst":{"address":address, "amount":"100@DFI", "domain": 2}}]) # Transfer 100 DFI from DVM to EVM From a96fd2210e9b45493a0d8d14fe50764bbb59f221 Mon Sep 17 00:00:00 2001 From: Bushstar <bushsolo@gmail.com> Date: Thu, 13 Jul 2023 10:43:54 +0100 Subject: [PATCH 2/4] Remove gas used check --- test/functional/feature_evm.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/functional/feature_evm.py b/test/functional/feature_evm.py index 4499f65aa4..76b36f9968 100755 --- a/test/functional/feature_evm.py +++ b/test/functional/feature_evm.py @@ -400,7 +400,6 @@ def run_test(self): # Check EVM blockhash eth_block = self.nodes[0].eth_getBlockByNumber('latest') eth_hash = eth_block['hash'][2:] - eth_fee = eth_block['gasUsed'][2:] block = self.nodes[0].getblock(self.nodes[0].getblockhash(self.nodes[0].getblockcount())) raw_tx = self.nodes[0].getrawtransaction(block['tx'][0], 1) block_hash = raw_tx['vout'][1]['scriptPubKey']['hex'][20:84] @@ -409,8 +408,6 @@ def run_test(self): # Check EVM miner fee opreturn_fee_amount = raw_tx['vout'][1]['scriptPubKey']['hex'][84:] opreturn_fee_sats = Decimal(int(opreturn_fee_amount[2:4] + opreturn_fee_amount[0:2], 16)) / 100000000 - eth_fee_sats = Decimal(int(Decimal(int(eth_fee, 16)) / 10)) / 100000000 - assert_equal(opreturn_fee_sats, eth_fee_sats) assert_equal(opreturn_fee_sats, miner_fee) # Test rollback of EVM TX From 03389edc2098882990fa1a0a404b7f7f501fff4b Mon Sep 17 00:00:00 2001 From: Bushstar <bushsolo@gmail.com> Date: Fri, 14 Jul 2023 06:47:50 +0100 Subject: [PATCH 3/4] Add TransferDomainLiveConfig --- src/masternodes/mn_checks.cpp | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index 9da7317f08..2f953bdb37 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -4018,8 +4018,13 @@ static Res ValidateTransferDomainScripts(const CScript &srcScript, const CScript return DeFiErrors::TransferDomainUnknownEdge(); } +struct TransferDomainLiveConfig { + bool dvmToEvm; + bool evmTodvm; +}; + Res ValidateTransferDomainEdge(const CTransaction &tx, - const CCustomCSView &mnview, + const TransferDomainLiveConfig &transferdomainConfig, uint32_t height, const CCoinsViewCache &coins, const Consensus::Params &consensus, @@ -4041,15 +4046,9 @@ Res ValidateTransferDomainEdge(const CTransaction &tx, if (src.amount.nTokenId != DCT_ID{0} || dst.amount.nTokenId != DCT_ID{0}) return DeFiErrors::TransferDomainIncorrectToken(); - CDataStructureV0 evm_dvm{AttributeTypes::Transfer, TransferIDs::Edges, TransferKeys::EVM_DVM}; - CDataStructureV0 dvm_evm{AttributeTypes::Transfer, TransferIDs::Edges, TransferKeys::DVM_EVM}; - - const auto attributes = mnview.GetAttributes(); - assert(attributes); - if (src.domain == static_cast<uint8_t>(VMDomain::DVM) && dst.domain == static_cast<uint8_t>(VMDomain::EVM)) { if (height >= static_cast<uint32_t>(consensus.ChangiIntermediateHeight4)) { - if (!attributes->GetValue(dvm_evm, false)) { + if (!transferdomainConfig.dvmToEvm) { return DeFiErrors::TransferDomainDVMEVMNotEnabled(); } } @@ -4062,7 +4061,7 @@ Res ValidateTransferDomainEdge(const CTransaction &tx, } else if (src.domain == static_cast<uint8_t>(VMDomain::EVM) && dst.domain == static_cast<uint8_t>(VMDomain::DVM)) { if (height >= static_cast<uint32_t>(consensus.ChangiIntermediateHeight4)) { - if (!attributes->GetValue(evm_dvm, false)) { + if (!transferdomainConfig.evmTodvm) { return DeFiErrors::TransferDomainEVMDVMNotEnabled(); } } @@ -4099,8 +4098,14 @@ Res ValidateTransferDomain(const CTransaction &tx, } } + CDataStructureV0 evm_dvm{AttributeTypes::Transfer, TransferIDs::Edges, TransferKeys::EVM_DVM}; + CDataStructureV0 dvm_evm{AttributeTypes::Transfer, TransferIDs::Edges, TransferKeys::DVM_EVM}; + const auto attributes = mnview.GetAttributes(); + assert(attributes); + TransferDomainLiveConfig transferdomainConfig{attributes->GetValue(dvm_evm, false), attributes->GetValue(evm_dvm, false)}; + for (const auto &[src, dst] : obj.transfers) { - auto res = ValidateTransferDomainEdge(tx, mnview, height, coins, consensus, src, dst); + auto res = ValidateTransferDomainEdge(tx, transferdomainConfig, height, coins, consensus, src, dst); if (!res) return res; } From df8d00d6b33acfe9cd9d091466f862ece45ff179 Mon Sep 17 00:00:00 2001 From: Bushstar <bushsolo@gmail.com> Date: Fri, 14 Jul 2023 08:18:23 +0100 Subject: [PATCH 4/4] Change value names. Auto enable on Changi fork. --- src/masternodes/govvariables/attributes.cpp | 4 ++-- src/masternodes/validation.cpp | 20 ++++++++++++++++++++ test/functional/feature_evm.py | 4 ++-- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/masternodes/govvariables/attributes.cpp b/src/masternodes/govvariables/attributes.cpp index 6aa2269f3b..236b1c4f7f 100644 --- a/src/masternodes/govvariables/attributes.cpp +++ b/src/masternodes/govvariables/attributes.cpp @@ -146,14 +146,14 @@ const std::map<uint8_t, std::string> &ATTRIBUTES::displayGovernanceIDs() { const std::map<std::string, uint8_t> &ATTRIBUTES::allowedTransferIDs() { static const std::map<std::string, uint8_t> params{ - {"edges", TransferIDs::Edges}, + {"allowed", TransferIDs::Edges}, }; return params; } const std::map<uint8_t, std::string> &ATTRIBUTES::displayTransferIDs() { static const std::map<uint8_t, std::string> params{ - {TransferIDs::Edges, "edges"}, + {TransferIDs::Edges, "allowed"}, }; return params; } diff --git a/src/masternodes/validation.cpp b/src/masternodes/validation.cpp index 140335b7fa..925041b667 100644 --- a/src/masternodes/validation.cpp +++ b/src/masternodes/validation.cpp @@ -2447,6 +2447,23 @@ static void ProcessEVMQueue(const CBlock &block, const CBlockIndex *pindex, CCus cache.AddBalance(minerAddress, {DCT_ID{}, static_cast<CAmount>(blockResult.miner_fee / CAMOUNT_TO_GWEI)}); } +static void ProcessChangiIntermediate4(const CBlockIndex* pindex, CCustomCSView& cache, const CChainParams& chainparams) { + if (pindex->nHeight != chainparams.GetConsensus().ChangiIntermediateHeight4 || IsRegtestNetwork()) { + return; + } + + auto attributes = cache.GetAttributes(); + assert(attributes); + + CDataStructureV0 evm_dvm{AttributeTypes::Transfer, TransferIDs::Edges, TransferKeys::EVM_DVM}; + CDataStructureV0 dvm_evm{AttributeTypes::Transfer, TransferIDs::Edges, TransferKeys::DVM_EVM}; + + attributes->SetValue(evm_dvm, true); + attributes->SetValue(dvm_evm, true); + + cache.SetVariable(*attributes); +} + void ProcessDeFiEvent(const CBlock &block, const CBlockIndex* pindex, CCustomCSView& mnview, const CCoinsViewCache& view, const CChainParams& chainparams, const CreationTxs &creationTxs, const uint64_t evmContext, std::array<uint8_t, 20>& beneficiary) { CCustomCSView cache(mnview); @@ -2504,6 +2521,9 @@ void ProcessDeFiEvent(const CBlock &block, const CBlockIndex* pindex, CCustomCSV // Execute EVM Queue ProcessEVMQueue(block, pindex, cache, chainparams, evmContext, beneficiary); + // Execute ChangiIntermediate4 Events. Delete when removing Changi forks + ProcessChangiIntermediate4(pindex, cache, chainparams); + // construct undo auto& flushable = cache.GetStorage(); auto undo = CUndo::Construct(mnview.GetStorage(), flushable.GetRaw()); diff --git a/test/functional/feature_evm.py b/test/functional/feature_evm.py index 76b36f9968..f79e5e7c4a 100755 --- a/test/functional/feature_evm.py +++ b/test/functional/feature_evm.py @@ -105,7 +105,7 @@ def run_test(self): assert_raises_rpc_error(-32600, "DVM to EVM is not currently enabled", self.nodes[0].transferdomain, [{"src": {"address":address, "amount":"100@DFI", "domain": 2}, "dst":{"address":eth_address, "amount":"100@DFI", "domain": 3}}]) # Activate transferdomain DVM to EVM - self.nodes[0].setgov({"ATTRIBUTES": {'v0/transferdomain/edges/dvm-evm': 'true'}}) + self.nodes[0].setgov({"ATTRIBUTES": {'v0/transferdomain/allowed/dvm-evm': 'true'}}) self.nodes[0].generate(1) # Check transferdomain without DFI balance before DFI address is funded @@ -163,7 +163,7 @@ def run_test(self): assert_raises_rpc_error(-32600, "EVM to DVM is not currently enabled", self.nodes[0].transferdomain, [{"src": {"address":address, "amount":"100@DFI", "domain": 3}, "dst":{"address":eth_address, "amount":"100@DFI", "domain": 2}}]) # Activate transferdomain DVM to EVM - self.nodes[0].setgov({"ATTRIBUTES": {'v0/transferdomain/edges/evm-dvm': 'true'}}) + self.nodes[0].setgov({"ATTRIBUTES": {'v0/transferdomain/allowed/evm-dvm': 'true'}}) self.nodes[0].generate(1) # Test not enough balance for EVM to DVM transfer