diff --git a/src/chainparams.cpp b/src/chainparams.cpp index fb4db3b9ec2..6bf772123c8 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 79302546c3c..e684b353711 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 1c9d1e4cf0d..bd26a246bb4 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 325bce1d0e1..236b1c4f7ff 100644 --- a/src/masternodes/govvariables/attributes.cpp +++ b/src/masternodes/govvariables/attributes.cpp @@ -51,27 +51,29 @@ const std::map &ATTRIBUTES::displayVersions() { const std::map &ATTRIBUTES::allowedTypes() { static const std::map 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 &ATTRIBUTES::displayTypes() { static const std::map 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 &ATTRIBUTES::displayGovernanceIDs() { return params; } +const std::map &ATTRIBUTES::allowedTransferIDs() { + static const std::map params{ + {"allowed", TransferIDs::Edges}, + }; + return params; +} + +const std::map &ATTRIBUTES::displayTransferIDs() { + static const std::map params{ + {TransferIDs::Edges, "allowed"}, + }; + return params; +} + const std::map> &ATTRIBUTES::allowedKeys() { static const std::map> keys{ {AttributeTypes::Token, @@ -197,6 +213,7 @@ const std::map> &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> &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> &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> &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( {DFIPKeys::EmissionUnusedFund, VerifyBool}, {DFIPKeys::MintTokens, VerifyBool}, {DFIPKeys::AllowDUSDLoops, VerifyBool}, + {DFIPKeys::TransferDomain, VerifyBool}, }}, {AttributeTypes::Locks, { @@ -628,6 +657,11 @@ const std::map( {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 7a1963767b2..973eb925cb9 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 &displayOracleIDs(); static const std::map &displayConsortiumIDs(); static const std::map &displayGovernanceIDs(); + static const std::map &displayTransferIDs(); static const std::map> &displayKeys(); Res RefundFuturesContracts(CCustomCSView &mnview, @@ -447,6 +459,7 @@ class ATTRIBUTES : public GovVariable, public AutoRegistrator &allowedOracleIDs(); static const std::map &allowedConsortiumIDs(); static const std::map &allowedGovernanceIDs(); + static const std::map &allowedTransferIDs(); static const std::map> &allowedKeys(); static const std::map(const std::string &)>>> &parseValue(); diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index 1b19725ee25..2f953bdb374 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -4018,11 +4018,18 @@ static Res ValidateTransferDomainScripts(const CScript &srcScript, const CScript return DeFiErrors::TransferDomainUnknownEdge(); } +struct TransferDomainLiveConfig { + bool dvmToEvm; + bool evmTodvm; +}; + Res ValidateTransferDomainEdge(const CTransaction &tx, + const TransferDomainLiveConfig &transferdomainConfig, 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(consensus.ChangiIntermediateHeight3)) { @@ -4040,6 +4047,12 @@ Res ValidateTransferDomainEdge(const CTransaction &tx, return DeFiErrors::TransferDomainIncorrectToken(); if (src.domain == static_cast(VMDomain::DVM) && dst.domain == static_cast(VMDomain::EVM)) { + if (height >= static_cast(consensus.ChangiIntermediateHeight4)) { + if (!transferdomainConfig.dvmToEvm) { + return DeFiErrors::TransferDomainDVMEVMNotEnabled(); + } + } + // DVM to EVM auto res = ValidateTransferDomainScripts(src.address, dst.address, VMDomainEdge::DVMToEVM); if (!res) return res; @@ -4047,6 +4060,12 @@ Res ValidateTransferDomainEdge(const CTransaction &tx, return HasAuth(tx, coins, src.address); } else if (src.domain == static_cast(VMDomain::EVM) && dst.domain == static_cast(VMDomain::DVM)) { + if (height >= static_cast(consensus.ChangiIntermediateHeight4)) { + if (!transferdomainConfig.evmTodvm) { + return DeFiErrors::TransferDomainEVMDVMNotEnabled(); + } + } + // EVM to DVM auto res = ValidateTransferDomainScripts(src.address, dst.address, VMDomainEdge::EVMToDVM); if (!res) return res; @@ -4069,14 +4088,24 @@ Res ValidateTransferDomain(const CTransaction &tx, return DeFiErrors::TransferDomainEVMNotEnabled(); } + if (!IsTransferDomainEnabled(height, mnview, consensus)) { + return DeFiErrors::TransferDomainNotEnabled(); + } + if (height >= static_cast(consensus.ChangiIntermediateHeight4)) { if (obj.transfers.size() < 1) { return DeFiErrors::TransferDomainInvalid(); } } + 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, height, coins, consensus, src, dst); + auto res = ValidateTransferDomainEdge(tx, transferdomainConfig, height, coins, consensus, src, dst); if (!res) return res; } @@ -5088,3 +5117,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 1e59fede46d..127629daeb3 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/src/masternodes/validation.cpp b/src/masternodes/validation.cpp index 140335b7fa0..925041b6677 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(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& 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 51d2663bf02..f79e5e7c4a5 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/allowed/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/allowed/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 @@ -373,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] @@ -382,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