diff --git a/src/init.cpp b/src/init.cpp index a89adc8bac..b530a09778 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -507,6 +507,7 @@ void SetupServerArgs() 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("-regtest-minttoken-simulate-mainnet", "Allow anybody to mint token on regtest", 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/mn_checks.cpp b/src/masternodes/mn_checks.cpp index 92bd376518..77ee494e81 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -586,7 +586,7 @@ class CCustomMetadataParseVisitor auto res = isPostGrandCentralFork(); return !res ? res : serialize(obj); } - + Res operator()(CCreatePropMessage& obj) const { auto res = isPostGrandCentralFork(); return !res ? res : serialize(obj); @@ -750,7 +750,7 @@ CAmount CCustomTxVisitor::CalculateTakerFee(CAmount amount) const return (arith_uint256(amount) * mnview.ICXGetTakerFeePerBTC() / COIN * GetDFIperBTC(pair->second) / COIN).GetLow64(); } -ResVal CCustomTxVisitor::MintableToken(DCT_ID id, const CTokenImplementation& token) const { +ResVal CCustomTxVisitor::MintableToken(DCT_ID id, const CTokenImplementation& token, bool anybodyCanMint) const { if (token.destructionTx != uint256{}) { return Res::Err("token %s already destroyed at height %i by tx %s", token.symbol, token.destructionHeight, token.destructionTx.GetHex()); @@ -776,23 +776,29 @@ ResVal CCustomTxVisitor::MintableToken(DCT_ID id, const CTokenImplement if (token.IsPoolShare()) { return Res::Err("can't mint LPS token %s!", id.ToString()); } - + static const auto isMainNet = Params().NetworkIDString() == CBaseChainParams::MAIN; // may be different logic with LPS, so, dedicated check: if (!token.IsMintable() || (isMainNet && mnview.GetLoanTokenByID(id))) { return Res::Err("token %s is not mintable!", id.ToString()); } - if (!HasAuth(auth.out.scriptPubKey)) { // in the case of DAT, it's ok to do not check foundation auth cause exact DAT owner is foundation member himself - if (!token.IsDAT()) { - return Res::Err("tx must have at least one input from token owner"); - } else if (!HasFoundationAuth()) { // Is a DAT, check founders auth - if (height < static_cast(consensus.GrandCentralHeight)) - return Res::Err("token is DAT and tx not from foundation member"); + ResVal result = {auth.out.scriptPubKey, Res::Ok()}; + if (anybodyCanMint || HasAuth(auth.out.scriptPubKey)) return result; + + // Historic: in the case of DAT, it's ok to do not check foundation auth cause exact DAT owner is foundation member himself + // The above is no longer true. + + if (token.IsDAT()) { + // Is a DAT, check founders auth + if (height < static_cast(consensus.GrandCentralHeight) && !HasFoundationAuth()) { + return Res::Err("token is DAT and tx not from foundation member"); } + } else { + return Res::Err("tx must have at least one input from token owner"); } - return {auth.out.scriptPubKey, Res::Ok()}; + return result; } Res CCustomTxVisitor::EraseEmptyBalances(TAmounts& balances) const @@ -1293,114 +1299,133 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor if (!token) return Res::Err("token %s does not exist!", tokenId.ToString()); - auto mintable = MintableToken(tokenId, *token); + // only on REGTEST and when flag is supplied + bool anybodyCanMint = (Params().NetworkIDString() != CBaseChainParams::REGTEST && !gArgs.GetArg("-regtest-minttoken-simulate-mainnet", false)); + + auto mintable = MintableToken(tokenId, *token, anybodyCanMint); + + auto mintTokensInternal = [&](DCT_ID tokenId, CAmount amount) { + auto minted = mnview.AddMintedTokens(tokenId, amount); + if (!minted) + return minted; + + CalculateOwnerRewards(*mintable.val); + auto res = mnview.AddBalance(*mintable.val, CTokenAmount{tokenId, amount}); + if (!res) + return res; + + return Res::Ok(); + }; + if (!mintable) return std::move(mintable); - - if (height >= static_cast(consensus.GrandCentralHeight) && token->IsDAT() && !HasFoundationAuth()) + if (anybodyCanMint || height < static_cast(consensus.GrandCentralHeight) || !token->IsDAT() || HasFoundationAuth()) { - auto attributes = mnview.GetAttributes(); - assert(attributes); + auto res = mintTokensInternal(tokenId, amount); + if (!res) return res; + continue; + } - CDataStructureV0 enableKey{AttributeTypes::Param, ParamIDs::Feature, DFIPKeys::ConsortiumEnabled}; - if (attributes->GetValue(enableKey, false)) - { - mintable.ok = false; + auto attributes = mnview.GetAttributes(); + assert(attributes); - CDataStructureV0 membersKey{AttributeTypes::Consortium, tokenId.v, ConsortiumKeys::MemberValues}; - const auto members = attributes->GetValue(membersKey, CConsortiumMembers{}); + CDataStructureV0 enableKey{AttributeTypes::Param, ParamIDs::Feature, DFIPKeys::ConsortiumEnabled}; + CDataStructureV0 membersKey{AttributeTypes::Consortium, tokenId.v, ConsortiumKeys::MemberValues}; + const auto members = attributes->GetValue(membersKey, CConsortiumMembers{}); - CDataStructureV0 membersMintedKey{AttributeTypes::Live, ParamIDs::Economy, EconomyKeys::ConsortiumMembersMinted}; - auto membersBalances = attributes->GetValue(membersMintedKey, CConsortiumMembersMinted{}); + if (!attributes->GetValue(enableKey, false) || members.empty()) { + const Coin& auth = coins.AccessCoin(COutPoint(token->creationTx, 1)); // always n=1 output + if (!HasAuth(auth.out.scriptPubKey)) + return Res::Err("You are not a foundation member or token owner and cannot mint this token!"); - const auto dailyInterval = height / consensus.blocksPerDay() * consensus.blocksPerDay(); + auto res = mintTokensInternal(tokenId, amount); + if (!res) return res; + continue; + } - for (auto const& [key, member] : members) - { - if (HasAuth(member.ownerAddress)) - { - if (member.status != CConsortiumMember::Status::Active) - return Res::Err("Cannot mint token, not an active member of consortium for %s!", token->symbol); - - auto add = SafeAdd(membersBalances[tokenId][key].minted, amount); - if (!add) - return (std::move(add)); - membersBalances[tokenId][key].minted = add; - - if (dailyInterval == membersBalances[tokenId][key].dailyMinted.first) { - add = SafeAdd(membersBalances[tokenId][key].dailyMinted.second, amount); - if (!add) - return (std::move(add)); - membersBalances[tokenId][key].dailyMinted.second = add; - } else { - membersBalances[tokenId][key].dailyMinted.first = dailyInterval; - membersBalances[tokenId][key].dailyMinted.second = amount; - } + mintable.ok = false; - if (membersBalances[tokenId][key].minted > member.mintLimit) - return Res::Err("You will exceed your maximum mint limit for %s token by minting this amount!", token->symbol); + CDataStructureV0 membersMintedKey{AttributeTypes::Live, ParamIDs::Economy, EconomyKeys::ConsortiumMembersMinted}; + auto membersBalances = attributes->GetValue(membersMintedKey, CConsortiumMembersMinted{}); - if (membersBalances[tokenId][key].dailyMinted.second > member.dailyMintLimit) { - return Res::Err("You will exceed your daily mint limit for %s token by minting this amount", token->symbol); - } + const auto dailyInterval = height / consensus.blocksPerDay() * consensus.blocksPerDay(); - *mintable.val = member.ownerAddress; - mintable.ok = true; - break; - } + for (auto const& [key, member] : members) + { + if (HasAuth(member.ownerAddress)) + { + if (member.status != CConsortiumMember::Status::Active) + return Res::Err("Cannot mint token, not an active member of consortium for %s!", token->symbol); + + auto add = SafeAdd(membersBalances[tokenId][key].minted, amount); + if (!add) + return (std::move(add)); + membersBalances[tokenId][key].minted = add; + + if (dailyInterval == membersBalances[tokenId][key].dailyMinted.first) { + add = SafeAdd(membersBalances[tokenId][key].dailyMinted.second, amount); + if (!add) + return (std::move(add)); + membersBalances[tokenId][key].dailyMinted.second = add; + } else { + membersBalances[tokenId][key].dailyMinted.first = dailyInterval; + membersBalances[tokenId][key].dailyMinted.second = amount; } - if (!mintable) - return Res::Err("You are not a foundation or consortium member and cannot mint this token!"); + if (membersBalances[tokenId][key].minted > member.mintLimit) + return Res::Err("You will exceed your maximum mint limit for %s token by minting this amount!", token->symbol); - CDataStructureV0 maxLimitKey{AttributeTypes::Consortium, tokenId.v, ConsortiumKeys::MintLimit}; - const auto maxLimit = attributes->GetValue(maxLimitKey, CAmount{0}); + if (membersBalances[tokenId][key].dailyMinted.second > member.dailyMintLimit) { + return Res::Err("You will exceed your daily mint limit for %s token by minting this amount", token->symbol); + } - CDataStructureV0 dailyLimitKey{AttributeTypes::Consortium, tokenId.v, ConsortiumKeys::DailyMintLimit}; - const auto dailyLimit = attributes->GetValue(dailyLimitKey, CAmount{0}); + *mintable.val = member.ownerAddress; + mintable.ok = true; + break; + } + } - CDataStructureV0 consortiumMintedKey{AttributeTypes::Live, ParamIDs::Economy, EconomyKeys::ConsortiumMinted}; - auto globalBalances = attributes->GetValue(consortiumMintedKey, CConsortiumGlobalMinted{}); + if (!mintable) + return Res::Err("You are not a foundation or consortium member and cannot mint this token!"); - auto add = SafeAdd(globalBalances[tokenId].minted, amount); - if (!add) - return (std::move(add)); + CDataStructureV0 maxLimitKey{AttributeTypes::Consortium, tokenId.v, ConsortiumKeys::MintLimit}; + const auto maxLimit = attributes->GetValue(maxLimitKey, CAmount{0}); - globalBalances[tokenId].minted = add; + CDataStructureV0 dailyLimitKey{AttributeTypes::Consortium, tokenId.v, ConsortiumKeys::DailyMintLimit}; + const auto dailyLimit = attributes->GetValue(dailyLimitKey, CAmount{0}); - if (maxLimit != -1 * COIN && globalBalances[tokenId].minted > maxLimit) - return Res::Err("You will exceed global maximum consortium mint limit for %s token by minting this amount!", token->symbol); + CDataStructureV0 consortiumMintedKey{AttributeTypes::Live, ParamIDs::Economy, EconomyKeys::ConsortiumMinted}; + auto globalBalances = attributes->GetValue(consortiumMintedKey, CConsortiumGlobalMinted{}); - CAmount totalDaily{}; - for (const auto& [key, value] : membersBalances[tokenId]) { - if (value.dailyMinted.first == dailyInterval) { - totalDaily += value.dailyMinted.second; - } - } + auto add = SafeAdd(globalBalances[tokenId].minted, amount); + if (!add) + return (std::move(add)); - if (dailyLimit != -1 * COIN && totalDaily > dailyLimit) - return Res::Err("You will exceed global daily maximum consortium mint limit for %s token by minting this amount.", token->symbol); + globalBalances[tokenId].minted = add; - attributes->SetValue(consortiumMintedKey, globalBalances); - attributes->SetValue(membersMintedKey, membersBalances); + if (maxLimit != -1 * COIN && globalBalances[tokenId].minted > maxLimit) + return Res::Err("You will exceed global maximum consortium mint limit for %s token by minting this amount!", token->symbol); - auto saved = mnview.SetVariable(*attributes); - if (!saved) - return saved; + CAmount totalDaily{}; + for (const auto& [key, value] : membersBalances[tokenId]) { + if (value.dailyMinted.first == dailyInterval) { + totalDaily += value.dailyMinted.second; } - else - return Res::Err("You are not a foundation member and cannot mint this token!"); } - auto minted = mnview.AddMintedTokens(tokenId, amount); - if (!minted) - return minted; + if (dailyLimit != -1 * COIN && totalDaily > dailyLimit) + return Res::Err("You will exceed global daily maximum consortium mint limit for %s token by minting this amount.", token->symbol); - CalculateOwnerRewards(*mintable.val); - auto res = mnview.AddBalance(*mintable.val, CTokenAmount{tokenId, amount}); - if (!res) - return res; + attributes->SetValue(consortiumMintedKey, globalBalances); + attributes->SetValue(membersMintedKey, membersBalances); + + auto saved = mnview.SetVariable(*attributes); + if (!saved) + return saved; + + auto minted = mintTokensInternal(tokenId, amount); + if (!minted) return minted; } return Res::Ok(); diff --git a/src/masternodes/mn_checks.h b/src/masternodes/mn_checks.h index 324c4ab9df..f4d1c2fe90 100644 --- a/src/masternodes/mn_checks.h +++ b/src/masternodes/mn_checks.h @@ -48,7 +48,7 @@ class CCustomTxVisitor DCT_ID FindTokenByPartialSymbolName(const std::string& symbol) const; CPoolPair GetBTCDFIPoolPair() const; CAmount CalculateTakerFee(CAmount amount) const; - ResVal MintableToken(DCT_ID id, const CTokenImplementation& token) const; + ResVal MintableToken(DCT_ID id, const CTokenImplementation& token, bool anybodyCanMint) const; Res EraseEmptyBalances(TAmounts& balances) const; Res SetShares(const CScript& owner, const TAmounts& balances) const; Res DelShares(const CScript& owner, const TAmounts& balances) const; diff --git a/src/masternodes/mn_rpc.cpp b/src/masternodes/mn_rpc.cpp index a650027f49..32e503dec0 100644 --- a/src/masternodes/mn_rpc.cpp +++ b/src/masternodes/mn_rpc.cpp @@ -203,7 +203,7 @@ static CTransactionRef send(CTransactionRef tx, CTransactionRef optAuthTx) { return tx; } -CWalletCoinsUnlocker::CWalletCoinsUnlocker(std::shared_ptr pwallet) : +CWalletCoinsUnlocker::CWalletCoinsUnlocker(std::shared_ptr pwallet) : pwallet(std::move(pwallet)) { } @@ -407,12 +407,7 @@ std::vector GetAuthInputsSmart(CWalletCoinsUnlocker& pwallet, int32_t txV // Look for founder's auth. minttoken may already have an auth in result. if (needFounderAuth && result.empty()) { auto anyFounder = AmIFounder(pwallet); - if (!anyFounder) { - // Called from minttokens if auth not empty here which can use collateralAddress - if (auths.empty()) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Need foundation member authorization"); - } - } else { + if (anyFounder) { auths.insert(anyFounder.value()); auto authInput = GetAnyFoundationAuthInput(pwallet); if (authInput) { @@ -838,7 +833,7 @@ UniValue listgovs(const JSONRPCRequest& request) { } else if (prefix == "attrs") { mode = GovVarsFilter::AttributesOnly; } else if (prefix == "v/2.7") { - // Undocumented. Make be removed or deprecated without notice. + // Undocumented. Make be removed or deprecated without notice. // Only here for unforeseen compatibility concern downstream // for transitions. mode = GovVarsFilter::Version2Dot7; @@ -878,7 +873,7 @@ UniValue listgovs(const JSONRPCRequest& request) { val = a->ExportFiltered(mode, prefix); } } else { - if (mode == GovVarsFilter::LiveAttributes || + if (mode == GovVarsFilter::LiveAttributes || mode == GovVarsFilter::PrefixedAttributes || mode == GovVarsFilter::AttributesOnly){ continue; diff --git a/src/masternodes/rpc_tokens.cpp b/src/masternodes/rpc_tokens.cpp index a278704e85..9a8647888c 100644 --- a/src/masternodes/rpc_tokens.cpp +++ b/src/masternodes/rpc_tokens.cpp @@ -728,10 +728,6 @@ UniValue minttokens(const JSONRPCRequest& request) { } } - if (needFoundersAuth && !AmIFounder(pwallet)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Need foundation or consortium member authorization!"); - } - rawTx.vin = GetAuthInputsSmart(pwallet, rawTx.nVersion, auths, needFoundersAuth, optAuthTx, txInputs); CDataStream metadata(DfTxMarker, SER_NETWORK, PROTOCOL_VERSION); diff --git a/test/functional/feature_consortium.py b/test/functional/feature_consortium.py index ec1de909cd..15d27737e6 100755 --- a/test/functional/feature_consortium.py +++ b/test/functional/feature_consortium.py @@ -14,10 +14,10 @@ def set_test_params(self): self.num_nodes = 4 self.setup_clean_chain = True self.extra_args = [ - ['-txnotokens=0', '-amkheight=50', '-bayfrontheight=50', '-bayfrontgardensheight=1', '-fortcanningheight=50', '-eunosheight=50', '-fortcanninghillheight=50', '-fortcanningparkheight=50', '-fortcanningroadheight=50', '-fortcanningcrunchheight=50', '-fortcanningspringheight=50', '-fortcanninggreatworldheight=250', '-grandcentralheight=254', '-txindex=1'], - ['-txnotokens=0', '-amkheight=50', '-bayfrontheight=50', '-bayfrontgardensheight=1', '-fortcanningheight=50', '-eunosheight=50', '-fortcanninghillheight=50', '-fortcanningparkheight=50', '-fortcanningroadheight=50', '-fortcanningcrunchheight=50', '-fortcanningspringheight=50', '-fortcanninggreatworldheight=250', '-grandcentralheight=254', '-txindex=1'], - ['-txnotokens=0', '-amkheight=50', '-bayfrontheight=50', '-bayfrontgardensheight=1', '-fortcanningheight=50', '-eunosheight=50', '-fortcanninghillheight=50', '-fortcanningparkheight=50', '-fortcanningroadheight=50', '-fortcanningcrunchheight=50', '-fortcanningspringheight=50', '-fortcanninggreatworldheight=250', '-grandcentralheight=254', '-txindex=1'], - ['-txnotokens=0', '-amkheight=50', '-bayfrontheight=50', '-bayfrontgardensheight=1', '-fortcanningheight=50', '-eunosheight=50', '-fortcanninghillheight=50', '-fortcanningparkheight=50', '-fortcanningroadheight=50', '-fortcanningcrunchheight=50', '-fortcanningspringheight=50', '-fortcanninggreatworldheight=250', '-grandcentralheight=254', '-txindex=1']] + ['-txnotokens=0', '-amkheight=50', '-bayfrontheight=50', '-bayfrontgardensheight=1', '-fortcanningheight=50', '-eunosheight=50', '-fortcanninghillheight=50', '-fortcanningparkheight=50', '-fortcanningroadheight=50', '-fortcanningcrunchheight=50', '-fortcanningspringheight=50', '-fortcanninggreatworldheight=250', '-grandcentralheight=254', '-regtest-minttoken-simulate-mainnet=1', '-txindex=1'], + ['-txnotokens=0', '-amkheight=50', '-bayfrontheight=50', '-bayfrontgardensheight=1', '-fortcanningheight=50', '-eunosheight=50', '-fortcanninghillheight=50', '-fortcanningparkheight=50', '-fortcanningroadheight=50', '-fortcanningcrunchheight=50', '-fortcanningspringheight=50', '-fortcanninggreatworldheight=250', '-grandcentralheight=254', '-regtest-minttoken-simulate-mainnet=1', '-txindex=1'], + ['-txnotokens=0', '-amkheight=50', '-bayfrontheight=50', '-bayfrontgardensheight=1', '-fortcanningheight=50', '-eunosheight=50', '-fortcanninghillheight=50', '-fortcanningparkheight=50', '-fortcanningroadheight=50', '-fortcanningcrunchheight=50', '-fortcanningspringheight=50', '-fortcanninggreatworldheight=250', '-grandcentralheight=254', '-regtest-minttoken-simulate-mainnet=1', '-txindex=1'], + ['-txnotokens=0', '-amkheight=50', '-bayfrontheight=50', '-bayfrontgardensheight=1', '-fortcanningheight=50', '-eunosheight=50', '-fortcanninghillheight=50', '-fortcanningparkheight=50', '-fortcanningroadheight=50', '-fortcanningcrunchheight=50', '-fortcanningspringheight=50', '-fortcanninggreatworldheight=250', '-grandcentralheight=254', '-regtest-minttoken-simulate-mainnet=1', '-txindex=1']] def run_test(self): @@ -30,7 +30,14 @@ def run_test(self): account2 = self.nodes[2].get_genesis_keys().ownerAuthAddress account3 = self.nodes[3].get_genesis_keys().ownerAuthAddress - self.nodes[1].generate(150) + self.nodes[1].generate(20) + self.sync_blocks() + + self.nodes[0].sendtoaddress(account1, 10) + self.nodes[0].sendtoaddress(account2, 10) + self.nodes[0].sendtoaddress(account3, 10) + + self.nodes[0].generate(1) self.sync_blocks() symbolBTC = "BTC" @@ -43,17 +50,16 @@ def run_test(self): "collateralAddress": account0 }) + self.nodes[0].generate(1) + self.sync_blocks() + self.nodes[0].createtoken({ "symbol": symbolDOGE, "name": "DOGE token", "isDAT": True, - "collateralAddress": account0 + "collateralAddress": account3 }) - self.nodes[0].sendtoaddress(account1, 10) - self.nodes[0].sendtoaddress(account2, 10) - self.nodes[0].sendtoaddress(account3, 10) - self.nodes[0].generate(1) self.sync_blocks() @@ -65,22 +71,26 @@ def run_test(self): 'from': account0, }) - self.nodes[0].generate(254 - self.nodes[0].getblockcount()) self.sync_blocks() - assert_raises_rpc_error(-5, "Need foundation or consortium member authorization", self.nodes[2].minttokens, ["1@" + symbolBTC]) - assert_raises_rpc_error(-5, "Need foundation or consortium member authorization", self.nodes[2].minttokens, ["1@" + symbolDOGE]) - assert_raises_rpc_error(-5, "Need foundation or consortium member authorization", self.nodes[3].minttokens, ["1@" + symbolBTC]) + # DAT owner can mint + self.nodes[3].minttokens(["1@" + symbolDOGE]) + self.nodes[3].generate(1) + self.sync_blocks() + + assert_raises_rpc_error(-32600, "You are not a foundation member or token owner and cannot mint this token", self.nodes[2].minttokens, ["1@" + symbolBTC]) + assert_raises_rpc_error(-32600, "You are not a foundation member or token owner and cannot mint this token", self.nodes[2].minttokens, ["1@" + symbolDOGE]) + assert_raises_rpc_error(-32600, "You are not a foundation member or token owner and cannot mint this token", self.nodes[3].minttokens, ["1@" + symbolBTC]) self.nodes[0].setgov({"ATTRIBUTES":{'v0/params/feature/consortium' : 'true'}}) self.nodes[0].generate(1) self.sync_blocks() - assert_raises_rpc_error(-5, "Need foundation or consortium member authorization", self.nodes[2].minttokens, ["1@" + symbolBTC]) - assert_raises_rpc_error(-5, "Need foundation or consortium member authorization", self.nodes[2].minttokens, ["1@" + symbolDOGE]) - assert_raises_rpc_error(-5, "Need foundation or consortium member authorization", self.nodes[3].minttokens, ["1@" + symbolBTC]) + assert_raises_rpc_error(-32600, "You are not a foundation member or token owner and cannot mint this token", self.nodes[2].minttokens, ["1@" + symbolBTC]) + assert_raises_rpc_error(-32600, "You are not a foundation member or token owner and cannot mint this token", self.nodes[2].minttokens, ["1@" + symbolDOGE]) + assert_raises_rpc_error(-32600, "You are not a foundation member or token owner and cannot mint this token", self.nodes[3].minttokens, ["1@" + symbolBTC]) # Set global mint limits self.nodes[0].setgov({"ATTRIBUTES":{'v0/consortium/' + idBTC + '/mint_limit' : '10', 'v0/consortium/' + idBTC + '/mint_limit_daily' : '10'}}) @@ -130,7 +140,7 @@ def run_test(self): assert_equal(attribs['v0/consortium/' + idBTC + '/members'], '{"01":{"name":"account2BTC","ownerAddress":"' + account2 +'","backingId":"ebf634ef7143bc5466995a385b842649b2037ea89d04d469bfa5ec29daf7d1cf","mintLimit":10.00000000,"dailyMintLimit":10.00000000,"status":0},"02":{"name":"account3BTC","ownerAddress":"' + account3 +'","backingId":"6c67fe93cad3d6a4982469a9b6708cdde2364f183d3698d3745f86eeb8ba99d5","mintLimit":4.00000000,"dailyMintLimit":4.00000000,"status":0}}') assert_equal(attribs['v0/consortium/' + idBTC + '/mint_limit'], '10') - assert_raises_rpc_error(-5, "Need foundation or consortium member authorization", self.nodes[2].minttokens, ["1@" + symbolDOGE]) + assert_raises_rpc_error(-32600, "You are not a foundation member or token owner and cannot mint this token", self.nodes[2].minttokens, ["1@" + symbolDOGE]) self.nodes[2].minttokens(["1@" + symbolBTC]) self.nodes[2].generate(1) @@ -170,6 +180,8 @@ def run_test(self): assert_equal(attribs['v0/consortium/' + idDOGE + '/mint_limit'], '6') assert_equal(attribs['v0/consortium/' + idDOGE + '/mint_limit_daily'], '6') + assert_raises_rpc_error(-32600, "You are not a foundation or consortium member and cannot mint this token", self.nodes[3].minttokens, ["1@" + symbolDOGE]) + self.nodes[2].minttokens(["2@" + symbolDOGE]) self.nodes[2].generate(1) self.sync_blocks() @@ -290,7 +302,7 @@ def run_test(self): attribs = self.nodes[0].getgov('ATTRIBUTES')['ATTRIBUTES'] assert_equal(attribs['v0/consortium/' + idDOGE + '/members'], '{"01":{"name":"account2DOGE","ownerAddress":"' + account2 +'","backingId":"ebf634ef7143bc5466995a385b842649b2037ea89d04d469bfa5ec29daf7d1cf","mintLimit":5.00000000,"dailyMintLimit":5.00000000,"status":1},"02":{"name":"account1DOGE","ownerAddress":"' + account1 +'","backingId":"ebf634ef7143bc5466995a385b842649b2037ea89d04d469bfa5ec29daf7d1cf","mintLimit":5.00000000,"dailyMintLimit":5.00000000,"status":0}}') - assert_equal(self.nodes[0].getburninfo(), {'address': 'mfburnZSAM7Gs1hpDeNaMotJXSGA7edosG', 'amount': Decimal('0E-8'), 'tokens': [], 'consortiumtokens': ['2.00000000@DOGE'], 'feeburn': Decimal('2.00000000'), 'auctionburn': Decimal('0E-8'), 'paybackburn': [], 'dexfeetokens': [], 'dfipaybackfee': Decimal('0E-8'), 'dfipaybacktokens': [], 'paybackfees': [], 'paybacktokens': [], 'emissionburn': Decimal('4892.89500000'), 'dfip2203': [], 'dfip2206f': []}) + assert_equal(self.nodes[0].getburninfo(), {'address': 'mfburnZSAM7Gs1hpDeNaMotJXSGA7edosG', 'amount': Decimal('0E-8'), 'tokens': [], 'consortiumtokens': ['2.00000000@DOGE'], 'feeburn': Decimal('2.00000000'), 'auctionburn': Decimal('0E-8'), 'paybackburn': [], 'dexfeetokens': [], 'dfipaybackfee': Decimal('0E-8'), 'dfipaybacktokens': [], 'paybackfees': [], 'paybacktokens': [], 'emissionburn': Decimal('4908.33000000'), 'dfip2203': [], 'dfip2206f': []}) assert_raises_rpc_error(-32600, "Cannot mint token, not an active member of consortium for DOGE!", self.nodes[2].minttokens, ["1@" + symbolDOGE]) @@ -455,13 +467,17 @@ def run_test(self): self.nodes[0].generate(1) self.sync_blocks() - assert_raises_rpc_error(-5, "Need foundation or consortium member authorization", self.nodes[2].minttokens, ["1@" + symbolBTC]) - assert_raises_rpc_error(-5, "Need foundation or consortium member authorization", self.nodes[2].minttokens, ["1@" + symbolDOGE]) - assert_raises_rpc_error(-5, "Need foundation or consortium member authorization", self.nodes[3].minttokens, ["1@" + symbolBTC]) + assert_raises_rpc_error(-32600, "You are not a foundation member or token owner and cannot mint this token", self.nodes[2].minttokens, ["1@" + symbolBTC]) + assert_raises_rpc_error(-32600, "You are not a foundation member or token owner and cannot mint this token", self.nodes[2].minttokens, ["1@" + symbolDOGE]) + assert_raises_rpc_error(-32600, "You are not a foundation member or token owner and cannot mint this token", self.nodes[3].minttokens, ["1@" + symbolBTC]) + + # DAT owner can mint again + self.nodes[3].minttokens(["1@" + symbolDOGE]) + self.nodes[3].generate(1) + self.sync_blocks() # Test unlimited limit - self.nodes[0].setgov({"ATTRIBUTES": {'v0/consortium/' + idBTC + - '/mint_limit': '-1', 'v0/consortium/' + idBTC + '/mint_limit_daily': '-1'}}) + self.nodes[0].setgov({"ATTRIBUTES": {'v0/consortium/' + idBTC + '/mint_limit': '-1', 'v0/consortium/' + idBTC + '/mint_limit_daily': '-1'}}) self.nodes[0].generate(1) self.sync_blocks() diff --git a/test/functional/feature_foundation_migration.py b/test/functional/feature_foundation_migration.py old mode 100644 new mode 100755 index d000251078..8a9eda9f37 --- a/test/functional/feature_foundation_migration.py +++ b/test/functional/feature_foundation_migration.py @@ -60,7 +60,7 @@ def run_test(self): assert_equal(self.nodes[0].getgov('ATTRIBUTES')['ATTRIBUTES']['v0/params/foundation/members'], '["bcrt1qyrfrpadwgw7p5eh3e9h3jmu4kwlz4prx73cqny","bcrt1qyeuu9rvq8a67j86pzvh5897afdmdjpyankp4mu","msER9bmJjyEemRpQoS8YYVL21VyZZrSgQ7"]') # Try and add self back in without foundation auth - assert_raises_rpc_error(-5, "Need foundation member authorization", self.nodes[0].setgov, {"ATTRIBUTES":{'v0/params/foundation/members':f'["{address}"]'}}) + assert_raises_rpc_error(-32600, "tx not from foundation member", self.nodes[0].setgov, {"ATTRIBUTES":{'v0/params/foundation/members':f'["{address}"]'}}) # Add address in from another node self.sync_blocks() @@ -99,7 +99,7 @@ def run_test(self): assert_equal(attributes['v0/params/dfip2203/active'], 'false') # Check disabling feature restores original usage. Node 0 fails here. - assert_raises_rpc_error(-5, "Need foundation member authorization", self.nodes[0].setgov, {"ATTRIBUTES":{'v0/params/foundation/members':f'["{address}"]'}}) + assert_raises_rpc_error(-32600, "tx not from foundation member", self.nodes[0].setgov, {"ATTRIBUTES":{'v0/params/foundation/members':f'["{address}"]'}}) self.nodes[1].setgov({"ATTRIBUTES":{'v0/params/feature/gov-foundation':'false'}}) self.nodes[1].generate(1) self.sync_blocks() diff --git a/test/functional/feature_oracles.py b/test/functional/feature_oracles.py index a8e39c475b..175f8b5a75 100755 --- a/test/functional/feature_oracles.py +++ b/test/functional/feature_oracles.py @@ -130,7 +130,7 @@ def run_test(self): price_feeds1 = [{"currency": "USD", "token": "GOLD"}, {"currency": "USD", "token": "PT"}] # check that only founder can appoint oracles - assert_raises_rpc_error(-5, 'Need foundation member authorization', + assert_raises_rpc_error(-32600, 'tx not from foundation member', self.nodes[2].appointoracle, oracle_address1, price_feeds1, 10) oracle_id1 = self.nodes[0].appointoracle(oracle_address1, price_feeds1, 10) @@ -151,7 +151,7 @@ def run_test(self): self.nodes[0].removeoracle(oracle_id2) # check that only founder can remove oracles - assert_raises_rpc_error(-5, 'Need foundation member authorization', + assert_raises_rpc_error(-32600, 'tx not from foundation member', self.nodes[2].removeoracle, oracle_id1) self.synchronize(node=0) @@ -238,7 +238,7 @@ def run_test(self): self.nodes[0].updateoracle(oracle_id1, oracle_address1, price_feeds1, 20) # check that only founder can appoint oracles - assert_raises_rpc_error(-5, 'Need foundation member authorization', + assert_raises_rpc_error(-32600, 'tx not from foundation member', self.nodes[2].updateoracle, oracle_id1, oracle_address1, price_feeds1, 10) self.synchronize(node=0) diff --git a/test/functional/feature_poolpair.py b/test/functional/feature_poolpair.py index 347c03ae9a..fe494e3d25 100755 --- a/test/functional/feature_poolpair.py +++ b/test/functional/feature_poolpair.py @@ -43,6 +43,9 @@ def run_test(self): self.nodes[0].generate(1) + node2 = self.nodes[2].getnewaddress("", "legacy") + self.nodes[0].sendtoaddress(node2, 1) + # 1 Creating DAT token self.nodes[0].createtoken({ "symbol": "PT", @@ -150,7 +153,7 @@ def run_test(self): }, []) except JSONRPCException as e: errorString = e.error['message'] - assert("Need foundation member authorization" in errorString) + assert("tx not from foundation member" in errorString) # 9 Checking pool existence p0 = self.nodes[0].getpoolpair("PTGOLD") diff --git a/test/functional/feature_tokens_dat.py b/test/functional/feature_tokens_dat.py index 1af4940fc3..d3cda0c573 100755 --- a/test/functional/feature_tokens_dat.py +++ b/test/functional/feature_tokens_dat.py @@ -43,6 +43,9 @@ def run_test(self): self.nodes[0].generate(1) + node2 = self.nodes[2].getnewaddress("", "legacy") + self.nodes[0].sendtoaddress(node2, 1) + # 1 Creating DAT token self.nodes[0].createtoken({ "symbol": "PT", @@ -104,7 +107,7 @@ def run_test(self): self.nodes[2].updatetoken("GOLD#128", {"isDAT": True}, []) except JSONRPCException as e: errorString = e.error['message'] - assert("Need foundation member authorization" in errorString) + assert("tx not from foundation member" in errorString) # 4.1 Trying to set smth else try: