|
30 | 30 | #include <txdb.h> |
31 | 31 | #include <txmempool.h> |
32 | 32 | #include <undo.h> |
| 33 | +#include <util/moneystr.h> |
33 | 34 | #include <util/ref.h> |
34 | 35 | #include <util/strencodings.h> |
35 | 36 | #include <util/system.h> |
@@ -1000,6 +1001,75 @@ static UniValue pruneblockchain(const JSONRPCRequest& request) |
1000 | 1001 | return uint64_t(block->nHeight); |
1001 | 1002 | } |
1002 | 1003 |
|
| 1004 | +static UniValue dumpcoinstats(const JSONRPCRequest& request) |
| 1005 | +{ |
| 1006 | + RPCHelpMan{"dumpcoinstats", |
| 1007 | + "\nDumps content of coinstats index to a CSV file.\n", |
| 1008 | + { |
| 1009 | + {"filename", RPCArg::Type::STR, RPCArg::Optional::NO, "The filename with path (absolute path recommended)"}, |
| 1010 | + }, |
| 1011 | + RPCResult{ |
| 1012 | + RPCResult::Type::OBJ, "", "", |
| 1013 | + { |
| 1014 | + {RPCResult::Type::STR, "filename", "The filename with full absolute path"}, |
| 1015 | + } |
| 1016 | + }, |
| 1017 | + RPCExamples{ |
| 1018 | + HelpExampleCli("dumpcoinstats", "\"test\"") + |
| 1019 | + HelpExampleRpc("dumpcoinstats", "\"test\"") |
| 1020 | + }, |
| 1021 | + }.Check(request); |
| 1022 | + |
| 1023 | + fs::path filepath = request.params[0].get_str(); |
| 1024 | + filepath = fs::absolute(filepath); |
| 1025 | + |
| 1026 | + if (fs::exists(filepath)) { |
| 1027 | + throw JSONRPCError(RPC_INVALID_PARAMETER, filepath.string() + " already exists. If you are sure this is what you want, move it out of the way first"); |
| 1028 | + } |
| 1029 | + |
| 1030 | + fsbridge::ofstream file; |
| 1031 | + file.open(filepath); |
| 1032 | + if (!file.is_open()) |
| 1033 | + throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open dump file"); |
| 1034 | + |
| 1035 | + if (!g_coin_stats_index) { |
| 1036 | + throw JSONRPCError(RPC_MISC_ERROR, "Coinstats index is not enabled"); |
| 1037 | + } |
| 1038 | + |
| 1039 | + file << strprintf("height,bestblock,txouts,bogosize,disk_size,total_amount,total_unspendable_amount,unspendable_amount,total_prevout_spent_amount,total_new_outputs_ex_coinbase_amount,coinbase_amount\n"); |
| 1040 | + |
| 1041 | + CCoinsStats stats; |
| 1042 | + CCoinsView* coins_view = WITH_LOCK(cs_main, return &ChainstateActive().CoinsDB()); |
| 1043 | + CBlockIndex *pindex = ::ChainActive().Genesis(); |
| 1044 | + NodeContext& node = EnsureNodeContext(request.context); |
| 1045 | + |
| 1046 | + for (; pindex; pindex = ::ChainActive().Next(pindex)) { |
| 1047 | + if (!GetUTXOStats(coins_view, stats, CoinStatsHashType::NONE, node.rpc_interruption_point, pindex)) |
| 1048 | + throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set"); |
| 1049 | + |
| 1050 | + file << strprintf("%d,", (int64_t)stats.nHeight); |
| 1051 | + file << strprintf("%s,", stats.hashBlock.GetHex()); |
| 1052 | + file << strprintf("%d,", (int64_t)stats.nTransactionOutputs); |
| 1053 | + file << strprintf("%d,", (int64_t)stats.nBogoSize); |
| 1054 | + file << strprintf("%d,", stats.nDiskSize); |
| 1055 | + file << strprintf("%s,", FormatMoney(stats.nTotalAmount)); |
| 1056 | + file << strprintf("%s,", FormatMoney(stats.total_unspendable_amount)); |
| 1057 | + file << strprintf("%s,", FormatMoney(stats.block_unspendable_amount)); |
| 1058 | + file << strprintf("%s,", FormatMoney(stats.block_prevout_spent_amount)); |
| 1059 | + file << strprintf("%s,", FormatMoney(stats.block_new_outputs_ex_coinbase_amount)); |
| 1060 | + file << strprintf("%s\n", FormatMoney(stats.block_coinbase_amount)); |
| 1061 | + |
| 1062 | + if (pindex->nHeight >= ::ChainActive().Tip()->nHeight) break; |
| 1063 | + } |
| 1064 | + |
| 1065 | + file.close(); |
| 1066 | + |
| 1067 | + UniValue response(UniValue::VOBJ); |
| 1068 | + response.pushKV("filename", filepath.string()); |
| 1069 | + |
| 1070 | + return response; |
| 1071 | +} |
| 1072 | + |
1003 | 1073 | static UniValue gettxoutsetinfo(const JSONRPCRequest& request) |
1004 | 1074 | { |
1005 | 1075 | RPCHelpMan{"gettxoutsetinfo", |
@@ -2436,6 +2506,7 @@ static const CRPCCommand commands[] = |
2436 | 2506 | { "blockchain", "getrawmempool", &getrawmempool, {"verbose"} }, |
2437 | 2507 | { "blockchain", "gettxout", &gettxout, {"txid","n","include_mempool"} }, |
2438 | 2508 | { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, {"hash_type", "hash_or_height", "verbose"} }, |
| 2509 | + { "blockchain", "dumpcoinstats", &dumpcoinstats, {"filename"} }, |
2439 | 2510 | { "blockchain", "pruneblockchain", &pruneblockchain, {"height"} }, |
2440 | 2511 | { "blockchain", "savemempool", &savemempool, {} }, |
2441 | 2512 | { "blockchain", "verifychain", &verifychain, {"checklevel","nblocks"} }, |
|
0 commit comments