|
8 | 8 | #include <node/mempool_persist.h>
|
9 | 9 |
|
10 | 10 | #include <chainparams.h>
|
| 11 | +#include <consensus/validation.h> |
11 | 12 | #include <core_io.h>
|
12 | 13 | #include <kernel/mempool_entry.h>
|
| 14 | +#include <net_processing.h> |
13 | 15 | #include <node/mempool_persist_args.h>
|
14 | 16 | #include <node/types.h>
|
15 | 17 | #include <policy/rbf.h>
|
|
24 | 26 | #include <util/moneystr.h>
|
25 | 27 | #include <util/strencodings.h>
|
26 | 28 | #include <util/time.h>
|
| 29 | +#include <util/vector.h> |
27 | 30 |
|
28 | 31 | #include <utility>
|
29 | 32 |
|
@@ -812,6 +815,104 @@ static RPCHelpMan savemempool()
|
812 | 815 | };
|
813 | 816 | }
|
814 | 817 |
|
| 818 | +static std::vector<RPCResult> OrphanDescription() |
| 819 | +{ |
| 820 | + return { |
| 821 | + RPCResult{RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"}, |
| 822 | + RPCResult{RPCResult::Type::STR_HEX, "wtxid", "The transaction witness hash in hex"}, |
| 823 | + RPCResult{RPCResult::Type::NUM, "bytes", "The serialized transaction size in bytes"}, |
| 824 | + RPCResult{RPCResult::Type::NUM, "vsize", "The virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted."}, |
| 825 | + RPCResult{RPCResult::Type::NUM, "weight", "The transaction weight as defined in BIP 141."}, |
| 826 | + RPCResult{RPCResult::Type::NUM_TIME, "expiration", "The orphan expiration time expressed in " + UNIX_EPOCH_TIME}, |
| 827 | + RPCResult{RPCResult::Type::ARR, "from", "", |
| 828 | + { |
| 829 | + RPCResult{RPCResult::Type::NUM, "peer_id", "Peer ID"}, |
| 830 | + }}, |
| 831 | + }; |
| 832 | +} |
| 833 | + |
| 834 | +static UniValue OrphanToJSON(const TxOrphanage::OrphanTxBase& orphan) |
| 835 | +{ |
| 836 | + UniValue o(UniValue::VOBJ); |
| 837 | + o.pushKV("txid", orphan.tx->GetHash().ToString()); |
| 838 | + o.pushKV("wtxid", orphan.tx->GetWitnessHash().ToString()); |
| 839 | + o.pushKV("bytes", orphan.tx->GetTotalSize()); |
| 840 | + o.pushKV("vsize", GetVirtualTransactionSize(*orphan.tx)); |
| 841 | + o.pushKV("weight", GetTransactionWeight(*orphan.tx)); |
| 842 | + o.pushKV("expiration", int64_t{TicksSinceEpoch<std::chrono::seconds>(orphan.nTimeExpire)}); |
| 843 | + UniValue from(UniValue::VARR); |
| 844 | + from.push_back(orphan.fromPeer); // only one fromPeer for now |
| 845 | + o.pushKV("from", from); |
| 846 | + return o; |
| 847 | +} |
| 848 | + |
| 849 | +static RPCHelpMan getorphantxs() |
| 850 | +{ |
| 851 | + return RPCHelpMan{"getorphantxs", |
| 852 | + "\nShows transactions in the tx orphanage.\n" |
| 853 | + "\nEXPERIMENTAL warning: this call may be changed in future releases.\n", |
| 854 | + { |
| 855 | + {"verbosity|verbose", RPCArg::Type::NUM, RPCArg::Default{0}, "0 for an array of txids (may contain duplicates), 1 for an array of objects with tx details, and 2 for details from (1) and tx hex", |
| 856 | + RPCArgOptions{.skip_type_check = true}}, |
| 857 | + }, |
| 858 | + { |
| 859 | + RPCResult{"for verbose = 0", |
| 860 | + RPCResult::Type::ARR, "", "", |
| 861 | + { |
| 862 | + {RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"}, |
| 863 | + }}, |
| 864 | + RPCResult{"for verbose = 1", |
| 865 | + RPCResult::Type::ARR, "", "", |
| 866 | + { |
| 867 | + {RPCResult::Type::OBJ, "", "", OrphanDescription()}, |
| 868 | + }}, |
| 869 | + RPCResult{"for verbose = 2", |
| 870 | + RPCResult::Type::ARR, "", "", |
| 871 | + { |
| 872 | + {RPCResult::Type::OBJ, "", "", |
| 873 | + Cat<std::vector<RPCResult>>( |
| 874 | + OrphanDescription(), |
| 875 | + {{RPCResult::Type::STR_HEX, "hex", "The serialized, hex-encoded transaction data"}} |
| 876 | + ) |
| 877 | + }, |
| 878 | + }}, |
| 879 | + }, |
| 880 | + RPCExamples{ |
| 881 | + HelpExampleCli("getorphantxs", "2") |
| 882 | + + HelpExampleRpc("getorphantxs", "2") |
| 883 | + }, |
| 884 | + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue |
| 885 | + { |
| 886 | + const NodeContext& node = EnsureAnyNodeContext(request.context); |
| 887 | + PeerManager& peerman = EnsurePeerman(node); |
| 888 | + std::vector<TxOrphanage::OrphanTxBase> orphanage = peerman.GetOrphanTransactions(); |
| 889 | + |
| 890 | + int verbosity{ParseVerbosity(request.params[0], /*default_verbosity=*/0)}; |
| 891 | + |
| 892 | + UniValue ret(UniValue::VARR); |
| 893 | + |
| 894 | + if (verbosity <= 0) { |
| 895 | + for (auto const& orphan : orphanage) { |
| 896 | + ret.push_back(orphan.tx->GetHash().ToString()); |
| 897 | + } |
| 898 | + } else if (verbosity == 1) { |
| 899 | + for (auto const& orphan : orphanage) { |
| 900 | + ret.push_back(OrphanToJSON(orphan)); |
| 901 | + } |
| 902 | + } else { |
| 903 | + // >= 2 |
| 904 | + for (auto const& orphan : orphanage) { |
| 905 | + UniValue o{OrphanToJSON(orphan)}; |
| 906 | + o.pushKV("hex", EncodeHexTx(*orphan.tx)); |
| 907 | + ret.push_back(o); |
| 908 | + } |
| 909 | + } |
| 910 | + |
| 911 | + return ret; |
| 912 | + }, |
| 913 | + }; |
| 914 | +} |
| 915 | + |
815 | 916 | static RPCHelpMan submitpackage()
|
816 | 917 | {
|
817 | 918 | return RPCHelpMan{"submitpackage",
|
@@ -1027,6 +1128,7 @@ void RegisterMempoolRPCCommands(CRPCTable& t)
|
1027 | 1128 | {"blockchain", &getrawmempool},
|
1028 | 1129 | {"blockchain", &importmempool},
|
1029 | 1130 | {"blockchain", &savemempool},
|
| 1131 | + {"hidden", &getorphantxs}, |
1030 | 1132 | {"rawtransactions", &submitpackage},
|
1031 | 1133 | };
|
1032 | 1134 | for (const auto& c : commands) {
|
|
0 commit comments