Skip to content

Commit 3a2bcb1

Browse files
authored
feat(rpc): Tweak protx info to be able to show info for a specific block (dashpay#4738)
1 parent 08b22dd commit 3a2bcb1

File tree

3 files changed

+56
-10
lines changed

3 files changed

+56
-10
lines changed

doc/release-notes-4738.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Updated RPCs
2+
------------
3+
4+
- `protx info`: It's now possible to get historical data at a specific block by providing its blockhash
5+

src/rpc/evo.cpp

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1270,25 +1270,39 @@ static bool CheckWalletOwnsScript(CWallet* pwallet, const CScript& script) {
12701270
}
12711271
#endif
12721272

1273-
static UniValue BuildDMNListEntry(CWallet* pwallet, const CDeterministicMN& dmn, bool detailed)
1273+
static UniValue BuildDMNListEntry(CWallet* pwallet, const CDeterministicMN& dmn, bool detailed, const ChainstateManager& chainman, const CBlockIndex* pindex = nullptr)
12741274
{
12751275
if (!detailed) {
12761276
return dmn.proTxHash.ToString();
12771277
}
12781278

12791279
UniValue o = dmn.ToJson();
12801280

1281+
CTransactionRef collateralTx{nullptr};
12811282
int confirmations = GetUTXOConfirmations(dmn.collateralOutpoint);
1283+
1284+
if (pindex != nullptr) {
1285+
if (confirmations > -1) {
1286+
confirmations -= WITH_LOCK(cs_main, return chainman.ActiveChain().Height()) - pindex->nHeight;
1287+
} else {
1288+
uint256 minedBlockHash;
1289+
collateralTx = GetTransaction(/* pindex */ nullptr, /* mempool */ nullptr, dmn.collateralOutpoint.hash, Params().GetConsensus(), minedBlockHash);
1290+
const CBlockIndex* const pindexMined = WITH_LOCK(cs_main, return chainman.m_blockman.LookupBlockIndex(minedBlockHash));
1291+
CHECK_NONFATAL(pindexMined != nullptr);
1292+
CHECK_NONFATAL(pindex->GetAncestor(pindexMined->nHeight) == pindexMined);
1293+
confirmations = pindex->nHeight - pindexMined->nHeight + 1;
1294+
}
1295+
}
12821296
o.pushKV("confirmations", confirmations);
12831297

12841298
#ifdef ENABLE_WALLET
12851299
bool hasOwnerKey = CheckWalletOwnsKey(pwallet, dmn.pdmnState->keyIDOwner);
12861300
bool hasVotingKey = CheckWalletOwnsKey(pwallet, dmn.pdmnState->keyIDVoting);
12871301

12881302
bool ownsCollateral = false;
1289-
uint256 tmpHashBlock;
1290-
CTransactionRef collateralTx = GetTransaction(/* block_index */ nullptr, /* mempool */ nullptr, dmn.collateralOutpoint.hash, Params().GetConsensus(), tmpHashBlock);
1291-
if (collateralTx) {
1303+
if (Coin coin; GetUTXOCoin(dmn.collateralOutpoint, coin)) {
1304+
ownsCollateral = CheckWalletOwnsScript(pwallet, coin.out.scriptPubKey);
1305+
} else if (collateralTx != nullptr) {
12921306
ownsCollateral = CheckWalletOwnsScript(pwallet, collateralTx->vout[dmn.collateralOutpoint.n].scriptPubKey);
12931307
}
12941308

@@ -1366,7 +1380,7 @@ static UniValue protx_list(const JSONRPCRequest& request, const ChainstateManage
13661380
CheckWalletOwnsKey(wallet.get(), dmn.pdmnState->keyIDVoting) ||
13671381
CheckWalletOwnsScript(wallet.get(), dmn.pdmnState->scriptPayout) ||
13681382
CheckWalletOwnsScript(wallet.get(), dmn.pdmnState->scriptOperatorPayout)) {
1369-
ret.push_back(BuildDMNListEntry(wallet.get(), dmn, detailed));
1383+
ret.push_back(BuildDMNListEntry(wallet.get(), dmn, detailed, chainman));
13701384
}
13711385
});
13721386
#endif
@@ -1389,7 +1403,7 @@ static UniValue protx_list(const JSONRPCRequest& request, const ChainstateManage
13891403
bool onlyEvoNodes = type == "evo";
13901404
mnList.ForEachMN(onlyValid, [&](const auto& dmn) {
13911405
if (onlyEvoNodes && dmn.nType != MnType::Evo) return;
1392-
ret.push_back(BuildDMNListEntry(wallet.get(), dmn, detailed));
1406+
ret.push_back(BuildDMNListEntry(wallet.get(), dmn, detailed, chainman));
13931407
});
13941408
} else {
13951409
throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid type specified");
@@ -1404,6 +1418,7 @@ static void protx_info_help(const JSONRPCRequest& request)
14041418
"\nReturns detailed information about a deterministic masternode.\n",
14051419
{
14061420
GetRpcArg("proTxHash"),
1421+
{"blockHash", RPCArg::Type::STR_HEX, /* default*/ "(chain tip)", "The hash of the block to get deterministic masternode state at"},
14071422
},
14081423
RPCResult{
14091424
RPCResult::Type::OBJ, "", "Details about a specific deterministic masternode",
@@ -1417,7 +1432,7 @@ static void protx_info_help(const JSONRPCRequest& request)
14171432
}.Check(request);
14181433
}
14191434

1420-
static UniValue protx_info(const JSONRPCRequest& request)
1435+
static UniValue protx_info(const JSONRPCRequest& request, const ChainstateManager& chainman)
14211436
{
14221437
protx_info_help(request);
14231438

@@ -1433,13 +1448,28 @@ static UniValue protx_info(const JSONRPCRequest& request)
14331448
g_txindex->BlockUntilSyncedToCurrentChain();
14341449
}
14351450

1451+
CBlockIndex* pindex{nullptr};
1452+
14361453
uint256 proTxHash(ParseHashV(request.params[0], "proTxHash"));
1437-
auto mnList = deterministicMNManager->GetListAtChainTip();
1454+
1455+
if (request.params[1].isNull()) {
1456+
LOCK(cs_main);
1457+
pindex = chainman.ActiveChain().Tip();
1458+
} else {
1459+
LOCK(cs_main);
1460+
uint256 blockHash(ParseHashV(request.params[1], "blockHash"));
1461+
pindex = chainman.m_blockman.LookupBlockIndex(blockHash);
1462+
if (pindex == nullptr) {
1463+
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1464+
}
1465+
}
1466+
1467+
auto mnList = deterministicMNManager->GetListForBlock(pindex);
14381468
auto dmn = mnList.GetMN(proTxHash);
14391469
if (!dmn) {
14401470
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s not found", proTxHash.ToString()));
14411471
}
1442-
return BuildDMNListEntry(wallet.get(), *dmn, true);
1472+
return BuildDMNListEntry(wallet.get(), *dmn, true, chainman, pindex);
14431473
}
14441474

14451475
static void protx_diff_help(const JSONRPCRequest& request)
@@ -1644,7 +1674,7 @@ static UniValue protx(const JSONRPCRequest& request)
16441674
if (command == "protxlist") {
16451675
return protx_list(new_request, chainman);
16461676
} else if (command == "protxinfo") {
1647-
return protx_info(new_request);
1677+
return protx_info(new_request, chainman);
16481678
} else if (command == "protxdiff") {
16491679
return protx_diff(new_request, chainman);
16501680
} else if (command == "protxlistdiff") {

test/functional/feature_dip3_deterministicmns.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,18 +109,29 @@ def run_test(self):
109109
self.assert_mnlists(mns)
110110

111111
self.log.info("test that MNs disappear from the list when the ProTx collateral is spent")
112+
# also make sure "protx info" returns correct historical data for spent collaterals
112113
spend_mns_count = 3
113114
mns_tmp = [] + mns
114115
dummy_txins = []
115116
old_tip = self.nodes[0].getblockcount()
116117
old_listdiff = self.nodes[0].protx("listdiff", 1, old_tip)
117118
for i in range(spend_mns_count):
119+
old_protx_hash = mns[i].protx_hash
120+
old_collateral_address = mns[i].collateral_address
121+
old_blockhash = self.nodes[0].getbestblockhash()
122+
old_rpc_info = self.nodes[0].protx("info", old_protx_hash)
123+
rpc_collateral_address = old_rpc_info["collateralAddress"]
124+
assert_equal(rpc_collateral_address, old_collateral_address)
118125
dummy_txin = self.spend_mn_collateral(mns[i], with_dummy_input_output=True)
119126
dummy_txins.append(dummy_txin)
120127
self.nodes[0].generate(1)
121128
self.sync_all()
122129
mns_tmp.remove(mns[i])
123130
self.assert_mnlists(mns_tmp)
131+
new_rpc_info = self.nodes[0].protx("info", old_protx_hash, old_blockhash)
132+
del old_rpc_info["metaInfo"]
133+
del new_rpc_info["metaInfo"]
134+
assert_equal(new_rpc_info, old_rpc_info)
124135
new_listdiff = self.nodes[0].protx("listdiff", 1, old_tip)
125136
assert_equal(new_listdiff, old_listdiff)
126137

0 commit comments

Comments
 (0)