diff --git a/src/dfi/rpc_masternodes.cpp b/src/dfi/rpc_masternodes.cpp index fb63aed14b..07f9be4d44 100644 --- a/src/dfi/rpc_masternodes.cpp +++ b/src/dfi/rpc_masternodes.cpp @@ -607,7 +607,7 @@ UniValue getmasternode(const JSONRPCRequest &request) { "getmasternode", "\nReturns information about specified masternode.\n", { - {"mn_id", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Masternode's id"}, + {"mn_id", RPCArg::Type::STR, RPCArg::Optional::NO, "Masternode's ID, operator or owner address"}, }, RPCResult{"{id:{...}} (object) Json object with masternode information\n"}, RPCExamples{HelpExampleCli("getmasternode", "mn_id") + HelpExampleRpc("getmasternode", "mn_id")}, @@ -621,15 +621,54 @@ UniValue getmasternode(const JSONRPCRequest &request) { } auto pwallet = GetWallet(request); - uint256 id = ParseHashV(request.params[0], "masternode id"); + const auto idStr = request.params[0].get_str(); LOCK(cs_main); const auto mnIds = pcustomcsview->GetOperatorsMulti(); - auto node = pcustomcsview->GetMasternode(id); - if (node) { - auto res = mnToJSON(*pcustomcsview, id, *node, true, mnIds, pwallet); // or maybe just node, w/o id? - return GetRPCResultCache().Set(request, res); + + auto printMasternode = [&](const uint256 &id) -> std::optional { + auto node = pcustomcsview->GetMasternode(id); + if (node) { + auto res = mnToJSON(*pcustomcsview, id, *node, true, mnIds, pwallet); + return GetRPCResultCache().Set(request, res); + } + return {}; + }; + + // Try from hex string + if (IsHex(idStr) && idStr.length() == 64) { + const auto id = uint256S(idStr); + if (auto res = printMasternode(id)) { + return *res; + } + } + + const auto dest = DecodeDestination(idStr); + if (!IsValidDestination(dest)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Masternode not found"); + } + + const auto keyId = CKeyID::TryFromDestination(dest); + if (!keyId) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Masternode not found"); + } + + // Try from operator address + auto hash = pcustomcsview->GetMasternodeIdByOperator(*keyId); + if (hash) { + if (auto res = printMasternode(*hash)) { + return *res; + } } + + // Try from owner address + hash = pcustomcsview->GetMasternodeIdByOwner(*keyId); + if (hash) { + if (auto res = printMasternode(*hash)) { + return *res; + } + } + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Masternode not found"); } diff --git a/test/functional/rpc_mn_basic.py b/test/functional/rpc_mn_basic.py index a78dbe4360..6f2d18c553 100755 --- a/test/functional/rpc_mn_basic.py +++ b/test/functional/rpc_mn_basic.py @@ -77,6 +77,10 @@ def run_test(self): # Create node0 self.nodes[0].generate(1) + + # Save start block for revert + start_block = self.nodes[0].getblockcount() + collateral1 = self.nodes[1].getnewaddress("", "legacy") assert_raises_rpc_error( -8, @@ -294,6 +298,40 @@ def run_test(self): self.nodes[0].generate(1) assert_equal(self.nodes[0].listmasternodes()[mnTx]["state"], "RESIGNED") + # Rollback to the start + self.rollback_to(start_block) + + # Generate separate owner and operator address + owner = self.nodes[0].getnewaddress("", "legacy") + operator = self.nodes[0].getnewaddress("", "legacy") + + # Create masternode + id = self.nodes[0].createmasternode(owner, operator) + self.nodes[0].generate(1) + + # Try and get MN with invalid string + assert_raises_rpc_error( + -5, + "Masternode not found", + self.nodes[0].getmasternode, + "notanid", + ) + + # Get masternode by ID + node = self.nodes[0].getmasternode(id)[id] + assert_equal(node["ownerAuthAddress"], owner) + assert_equal(node["operatorAuthAddress"], operator) + + # Get masternode by owner + node = self.nodes[0].getmasternode(owner)[id] + assert_equal(node["ownerAuthAddress"], owner) + assert_equal(node["operatorAuthAddress"], operator) + + # Get masternode by operator + node = self.nodes[0].getmasternode(operator)[id] + assert_equal(node["ownerAuthAddress"], owner) + assert_equal(node["operatorAuthAddress"], operator) + if __name__ == "__main__": MasternodesRpcBasicTest().main()