From a92ae132e2466dcde37d9df1a193452b62e2186e Mon Sep 17 00:00:00 2001 From: jamescowens Date: Sun, 4 Sep 2022 01:59:28 -0400 Subject: [PATCH] Implementation of getmrcinfo This provides an rpc command to get a summary and if desired details of MRC payments. --- src/main.cpp | 2 +- src/rpc/blockchain.cpp | 159 +++++++++++++++++++++++++++++++++++++++++ src/rpc/client.cpp | 3 + src/rpc/server.cpp | 1 + src/rpc/server.h | 1 + 5 files changed, 165 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index d7e6302af8..2335e4a325 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3108,7 +3108,7 @@ GRC::MRCFees CBlock::GetMRCFees() const EXCLUSIVE_LOCKS_REQUIRED(cs_main) Fraction foundation_fee_fraction = FoundationSideStakeAllocation(); - const GRC::Claim claim = NCONST_PTR(this)->PullClaim(); + const GRC::Claim claim = GetClaim(); CAmount mrc_total_fees = 0; diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 9a36a8d700..02140ce159 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -460,6 +460,165 @@ UniValue dumpcontracts(const UniValue& params, bool fHelp) return report; } +UniValue getmrcinfo(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() > 3) + throw runtime_error( + "getmrcinfo [detailed MRC info [low height [high height]]]\n" + "\n" + "[detailed MRC info]: optional boolean to output MRC details.\n" + " Defaults to false.\n" + "[low height]: optional low height for scope.\n" + " Defaults to V12 block height.\n" + "[high height]: optional high height for scope.\n" + " Defaults to current block.\n" + ); + + bool output_mrc_details = false; + + if (params.size() > 0) { + output_mrc_details = params[0].get_bool(); + } + + // No MRC's below V12 block height. + int low_height = Params().GetConsensus().BlockV12Height; + int high_height = 0; + + if (params.size() > 1) { + // If specified low height is lower than V12 height, set to V12 height. + low_height = std::max(params[1].get_int(), low_height); + } + + if (params.size() > 2) { + // High height can't be lower than the low height. + high_height = std::max(low_height, params[2].get_int()); + } + + UniValue report(UniValue::VOBJ); + UniValue block_output_array(UniValue::VARR); + + uint64_t total_mrcs_paid = 0; + uint64_t total_mrc_requests = 0; + + CAmount mrc_total_research_rewards = 0; + CAmount mrc_total_foundation_fees = 0; + CAmount mrc_total_staker_fees = 0; + + CBlock block; + UniValue block_output(UniValue::VOBJ); + + LOCK(cs_main); + + // Set default high_height here if not specified above now that lock on cs_main is taken. + if (!high_height) { + high_height = pindexBest->nHeight; + } + + CBlockIndex* blockindex = pindexBest; + + // Rewind to low height. + for (; blockindex; blockindex = blockindex->pprev) { + if (blockindex->nHeight == low_height) break; + } + + while (blockindex && blockindex->nHeight <= high_height) { + CAmount mrc_research_rewards = 0; + + for (const auto& mrc_context : blockindex->m_mrc_researchers) { + mrc_research_rewards += mrc_context->m_research_subsidy; + } + + ReadBlockFromDisk(block, blockindex, Params().GetConsensus()); + + // Get the claim which is where MRCs are actually paid. + GRC::Claim claim = block.GetClaim(); + GRC::MRCFees mrc_fees = block.GetMRCFees(); + + uint64_t mrcs_paid = claim.m_mrc_tx_map.size(); // This also matches the size of the blockindex->m_mrc_researchers + uint64_t mrc_requests = 0; + + if (output_mrc_details) { + UniValue mrc_requests_output_array(UniValue::VARR); + + block_output.pushKV("hash", block.GetHash().GetHex()); + block_output.pushKV("height", blockindex->nHeight); + block_output.pushKV("mrc_research_rewards", ValueFromAmount(mrc_research_rewards)); + block_output.pushKV("mrc_foundation_fees", ValueFromAmount(mrc_fees.m_mrc_foundation_fees)); + block_output.pushKV("mrc_staker_fees", ValueFromAmount(mrc_fees.m_mrc_staker_fees)); + block_output.pushKV("mrc_net_paid_to_researchers", ValueFromAmount(mrc_research_rewards + - mrc_fees.m_mrc_foundation_fees + - mrc_fees.m_mrc_staker_fees)); + block_output.pushKV("mrcs_paid", mrcs_paid); + block_output.pushKV("claim", ClaimToJson(block.GetClaim(), blockindex)); + + for (const auto& tx : block.vtx) { + for (const auto& contract : tx.GetContracts()) { + // We are only interested in MRC request contracts here. + if (contract.m_type != GRC::ContractType::MRC) continue; + + ++mrc_requests; + + bool mrc_paid_in_claim = false; + + for (const auto& iter : claim.m_mrc_tx_map) { + if (tx.GetHash() == iter.second) { + mrc_paid_in_claim = true; + break; + } + } + + UniValue mrc_output(UniValue::VOBJ); + + mrc_output.pushKV("txid", tx.GetHash().GetHex()); + mrc_output.pushKVs(MRCToJson(contract.CopyPayloadAs())); + mrc_output.pushKV("mrc_request_paid", mrc_paid_in_claim); + + mrc_requests_output_array.push_back(mrc_output); + + } // contracts + } // transaction + + block_output.pushKV("mrc_requests", mrc_requests_output_array); + block_output.pushKV("mrc_requests_not_paid", mrc_requests - mrcs_paid); + + if (mrc_requests) { + block_output_array.push_back(block_output); + } + } else { + for (const auto& tx : block.vtx) { + for (const auto& contract : tx.GetContracts()) { + // We are only interested in MRC request contracts here. + if (contract.m_type != GRC::ContractType::MRC) continue; + + ++mrc_requests; + } // contracts + } // transaction + } + + mrc_total_foundation_fees += mrc_fees.m_mrc_foundation_fees; + mrc_total_staker_fees += mrc_fees.m_mrc_staker_fees; + total_mrc_requests += mrc_requests; + total_mrcs_paid += mrcs_paid; + mrc_total_research_rewards += mrc_research_rewards; + blockindex = blockindex->pnext; + } // while (pblockindex...) + + report.pushKV("total_mrcs_paid", total_mrcs_paid); + report.pushKV("total_mrc_requests", total_mrc_requests); + report.pushKV("total_mrc_requests_not_paid", total_mrc_requests - total_mrcs_paid); + report.pushKV("mrc_total_research_rewards", ValueFromAmount(mrc_total_research_rewards)); + report.pushKV("mrc_total_foundation_fees", ValueFromAmount(mrc_total_foundation_fees)); + report.pushKV("mrc_total_staker_fees", ValueFromAmount(mrc_total_staker_fees)); + report.pushKV("mrc_total_net_paid_to_researchers", ValueFromAmount(mrc_total_research_rewards + - mrc_total_foundation_fees + - mrc_total_staker_fees)); + if (output_mrc_details) { + report.pushKV("mrc_details_by_block", block_output_array); + } + + return report; +} + UniValue showblock(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index b2af33fa03..988476b25b 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -191,6 +191,9 @@ static const CRPCConvertParam vRPCConvertParams[] = { "beaconreport" , 0 }, { "createmrcrequest" , 0 }, { "createmrcrequest" , 1 }, + { "getmrcinfo" , 0 }, + { "getmrcinfo" , 1 }, + { "getmrcinfo" , 2 }, { "superblocks" , 0 }, { "superblocks" , 1 }, diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 5ca1f2b253..90d6093c73 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -355,6 +355,7 @@ static const CRPCCommand vRPCCommands[] = { "createmrcrequest", &createmrcrequest, cat_staking }, { "explainmagnitude", &explainmagnitude, cat_staking }, { "getlaststake", &getlaststake, cat_staking }, + { "getmrcinfo", &getmrcinfo, cat_staking }, { "getstakinginfo", &getstakinginfo, cat_staking }, { "getmininginfo", &getstakinginfo, cat_staking }, //alias for getstakinginfo (compatibility) { "lifetime", &lifetime, cat_staking }, diff --git a/src/rpc/server.h b/src/rpc/server.h index 4885d4c3f9..2990137d1f 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -171,6 +171,7 @@ extern UniValue beaconstatus(const UniValue& params, bool fHelp); extern UniValue createmrcrequest(const UniValue& params, const bool fHelp); extern UniValue explainmagnitude(const UniValue& params, bool fHelp); extern UniValue getlaststake(const UniValue& params, bool fHelp); +extern UniValue getmrcinfo(const UniValue& params, bool fHelp); extern UniValue getstakinginfo(const UniValue& params, bool fHelp); extern UniValue lifetime(const UniValue& params, bool fHelp); extern UniValue magnitude(const UniValue& params, bool fHelp);