mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 20:12:57 +01:00
feat: new rpc getrawtransactionmulti (#5839)
## Issue being fixed or feature implemented For platform needs `getrawtransactionmulti` will help to reduce amount of rpc calls for sake of performance improvement. ## What was done? Implemented new RPC, basic functional test, release note. ## How Has This Been Tested? On testnet: ``` > getrawtransactionmulti '{"000000abbe61a4d9b9356cb1d7deb1132d0b444a62869e71c2f3aa8ce2361359":["6e3ef19a3f955ac75a1f84dae60d42bbe11548ef54e37033ff2d91b3c4a09e9c", "415d5fafd5ee24ada8b99c36df339785a3066170c0dca6bb1aa6a5b96cf51e35"], "0":["ec7090f01c0e9b6e29d3be8810b12c780d2fb34372a53b231ce18bb7d2f1e8b0"]}' > getrawtransactionmulti '{"000000abbe61a4d9b9356cb1d7deb1132d0b444a62869e71c2f3aa8ce2361359":["6e3ef19a3f955ac75a1f84dae60d42bbe11548ef54e37033ff2d91b3c4a09e9c", "415d5fafd5ee24ada8b99c36df339785a3066170c0dca6bb1aa6a5b96cf51e35"], "0":["ec7090f01c0e9b6e29d3be8810b12c780d2fb34372a53b231ce18bb7d2f1e8b0"]}' true ``` ## Breaking Changes N/A ## Checklist: - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have added or updated relevant unit/integration/functional/e2e tests - [x] I have made corresponding changes to the documentation - [x] I have assigned this pull request to a milestone --------- Co-authored-by: pasta <pasta@dashboost.org>
This commit is contained in:
parent
3d9dc207cf
commit
d17665307b
4
doc/release-notes-5839.md
Normal file
4
doc/release-notes-5839.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
RPC changes
|
||||||
|
-----------
|
||||||
|
|
||||||
|
New RPC getrawtransactionmulti that can return batch up to 100 rawtransaction at one request.
|
@ -107,6 +107,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
|||||||
{ "gettransaction", 1, "include_watchonly" },
|
{ "gettransaction", 1, "include_watchonly" },
|
||||||
{ "gettransaction", 2, "verbose" },
|
{ "gettransaction", 2, "verbose" },
|
||||||
{ "getrawtransaction", 1, "verbose" },
|
{ "getrawtransaction", 1, "verbose" },
|
||||||
|
{ "getrawtransactionmulti", 0, "txid_map" },
|
||||||
|
{ "getrawtransactionmulti", 1, "verbose" },
|
||||||
{ "gettxchainlocks", 0, "txids" },
|
{ "gettxchainlocks", 0, "txids" },
|
||||||
{ "createrawtransaction", 0, "inputs" },
|
{ "createrawtransaction", 0, "inputs" },
|
||||||
{ "createrawtransaction", 1, "outputs" },
|
{ "createrawtransaction", 1, "outputs" },
|
||||||
|
@ -265,6 +265,91 @@ static UniValue getrawtransaction(const JSONRPCRequest& request)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static UniValue getrawtransactionmulti(const JSONRPCRequest& request) {
|
||||||
|
RPCHelpMan{
|
||||||
|
"getrawtransactionmulti",
|
||||||
|
"\nReturns the raw transaction data for multiple transactions.\n"
|
||||||
|
"\nThis call is an extension of getrawtransaction that supports multiple transactions.\n"
|
||||||
|
"It accepts a map of block hashes to a list of transaction hashes.\n"
|
||||||
|
"A block hash of 0 indicates transactions not yet mined or in the mempool.\n",
|
||||||
|
{
|
||||||
|
{"transactions", RPCArg::Type::OBJ, RPCArg::Optional::NO,
|
||||||
|
"A JSON object with block hashes as keys and lists of transaction hashes as values (no more than 100 in total)",
|
||||||
|
{
|
||||||
|
{"blockhash", RPCArg::Type::ARR, RPCArg::Optional::OMITTED,
|
||||||
|
"The block hash and the list of transaction ids to fetch",
|
||||||
|
{
|
||||||
|
{"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "The transaction id"},
|
||||||
|
}},
|
||||||
|
}},
|
||||||
|
{"verbose", RPCArg::Type::BOOL, /* default */ "false",
|
||||||
|
"If false, return a string, otherwise return a json object"},
|
||||||
|
},
|
||||||
|
RPCResults{},
|
||||||
|
RPCExamples{
|
||||||
|
HelpExampleCli("getrawtransactionmulti",
|
||||||
|
R"('{"blockhash1":["txid1","txid2"], "0":["txid3"]}')")
|
||||||
|
+ HelpExampleRpc("getrawtransactionmulti",
|
||||||
|
R"('{"blockhash1":["txid1","txid2"], "0":["txid3"]})")
|
||||||
|
},
|
||||||
|
}.Check(request);
|
||||||
|
|
||||||
|
// Parse arguments
|
||||||
|
UniValue transactions{request.params[0].get_obj()};
|
||||||
|
// Accept either a bool (true) or a num (>=1) to indicate verbose output.
|
||||||
|
bool fVerbose{false};
|
||||||
|
if (!request.params[1].isNull()) {
|
||||||
|
fVerbose = request.params[1].isNum() ? (request.params[1].get_int() != 0) : request.params[1].get_bool();
|
||||||
|
}
|
||||||
|
|
||||||
|
const NodeContext& node{EnsureAnyNodeContext(request.context)};
|
||||||
|
const ChainstateManager& chainman{EnsureChainman(node)};
|
||||||
|
const LLMQContext& llmq_ctx{EnsureLLMQContext(node)};
|
||||||
|
CTxMemPool& mempool{EnsureMemPool(node)};
|
||||||
|
|
||||||
|
if (transactions.size() > 100) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Up to 100 blocks and txids only");
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t count{0};
|
||||||
|
UniValue result(UniValue::VOBJ);
|
||||||
|
for (const std::string& blockhash_str : transactions.getKeys()) {
|
||||||
|
const uint256 blockhash{uint256S(blockhash_str)};
|
||||||
|
const UniValue txids = transactions[blockhash_str].get_array();
|
||||||
|
|
||||||
|
CBlockIndex* blockindex{blockhash.IsNull() ? nullptr : WITH_LOCK(::cs_main, return chainman.m_blockman.LookupBlockIndex(blockhash))};
|
||||||
|
if (blockindex == nullptr && !blockhash.IsNull()) {
|
||||||
|
for (const auto idx : irange::range(txids.size())) {
|
||||||
|
result.pushKV(txids[idx].get_str(), "None");
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
count += txids.size();
|
||||||
|
if (count > 100) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Up to 100 txids in total");
|
||||||
|
}
|
||||||
|
for (const auto idx : irange::range(txids.size())) {
|
||||||
|
const std::string txid_str = txids[idx].get_str();
|
||||||
|
const uint256 txid = ParseHashV(txid_str, "transaction id");
|
||||||
|
|
||||||
|
uint256 hash_block;
|
||||||
|
const CTransactionRef tx = GetTransaction(blockindex, &mempool, txid, Params().GetConsensus(), hash_block);
|
||||||
|
if (!tx) {
|
||||||
|
result.pushKV(txid_str, "None");
|
||||||
|
} else if (fVerbose) {
|
||||||
|
UniValue tx_data{UniValue::VOBJ};
|
||||||
|
TxToJSON(*tx, hash_block, mempool, chainman.ActiveChainstate(), *llmq_ctx.clhandler, *llmq_ctx.isman, tx_data);
|
||||||
|
result.pushKV(txid_str, tx_data);
|
||||||
|
} else {
|
||||||
|
result.pushKV(txid_str, EncodeHexTx(*tx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static UniValue gettxchainlocks(const JSONRPCRequest& request)
|
static UniValue gettxchainlocks(const JSONRPCRequest& request)
|
||||||
{
|
{
|
||||||
RPCHelpMan{
|
RPCHelpMan{
|
||||||
@ -1885,6 +1970,7 @@ static const CRPCCommand commands[] =
|
|||||||
// --------------------- ------------------------ ----------------------- ----------
|
// --------------------- ------------------------ ----------------------- ----------
|
||||||
{ "rawtransactions", "getassetunlockstatuses", &getassetunlockstatuses, {"indexes"} },
|
{ "rawtransactions", "getassetunlockstatuses", &getassetunlockstatuses, {"indexes"} },
|
||||||
{ "rawtransactions", "getrawtransaction", &getrawtransaction, {"txid","verbose","blockhash"} },
|
{ "rawtransactions", "getrawtransaction", &getrawtransaction, {"txid","verbose","blockhash"} },
|
||||||
|
{ "rawtransactions", "getrawtransactionmulti", &getrawtransactionmulti, {"txid_map","verbose"} },
|
||||||
{ "rawtransactions", "gettxchainlocks", &gettxchainlocks, {"txids"} },
|
{ "rawtransactions", "gettxchainlocks", &gettxchainlocks, {"txids"} },
|
||||||
{ "rawtransactions", "createrawtransaction", &createrawtransaction, {"inputs","outputs","locktime"} },
|
{ "rawtransactions", "createrawtransaction", &createrawtransaction, {"inputs","outputs","locktime"} },
|
||||||
{ "rawtransactions", "decoderawtransaction", &decoderawtransaction, {"hexstring"} },
|
{ "rawtransactions", "decoderawtransaction", &decoderawtransaction, {"hexstring"} },
|
||||||
|
@ -306,19 +306,24 @@ class RawTransactionsTest(BitcoinTestFramework):
|
|||||||
# 1. valid parameters - only supply txid
|
# 1. valid parameters - only supply txid
|
||||||
txId = rawTx["txid"]
|
txId = rawTx["txid"]
|
||||||
assert_equal(self.nodes[0].getrawtransaction(txId), rawTxSigned['hex'])
|
assert_equal(self.nodes[0].getrawtransaction(txId), rawTxSigned['hex'])
|
||||||
|
assert_equal(self.nodes[0].getrawtransactionmulti({"0":[txId]})[txId], rawTxSigned['hex'])
|
||||||
|
|
||||||
# 2. valid parameters - supply txid and 0 for non-verbose
|
# 2. valid parameters - supply txid and 0 for non-verbose
|
||||||
assert_equal(self.nodes[0].getrawtransaction(txId, 0), rawTxSigned['hex'])
|
assert_equal(self.nodes[0].getrawtransaction(txId, 0), rawTxSigned['hex'])
|
||||||
|
assert_equal(self.nodes[0].getrawtransactionmulti({"0":[txId]}, 0)[txId], rawTxSigned['hex'])
|
||||||
|
|
||||||
# 3. valid parameters - supply txid and False for non-verbose
|
# 3. valid parameters - supply txid and False for non-verbose
|
||||||
assert_equal(self.nodes[0].getrawtransaction(txId, False), rawTxSigned['hex'])
|
assert_equal(self.nodes[0].getrawtransaction(txId, False), rawTxSigned['hex'])
|
||||||
|
assert_equal(self.nodes[0].getrawtransactionmulti({"0":[txId]}, False)[txId], rawTxSigned['hex'])
|
||||||
|
|
||||||
# 4. valid parameters - supply txid and 1 for verbose.
|
# 4. valid parameters - supply txid and 1 for verbose.
|
||||||
# We only check the "hex" field of the output so we don't need to update this test every time the output format changes.
|
# We only check the "hex" field of the output so we don't need to update this test every time the output format changes.
|
||||||
assert_equal(self.nodes[0].getrawtransaction(txId, 1)["hex"], rawTxSigned['hex'])
|
assert_equal(self.nodes[0].getrawtransaction(txId, 1)["hex"], rawTxSigned['hex'])
|
||||||
|
assert_equal(self.nodes[0].getrawtransactionmulti({"0":[txId]}, 1)[txId]['hex'], rawTxSigned['hex'])
|
||||||
|
|
||||||
# 5. valid parameters - supply txid and True for non-verbose
|
# 5. valid parameters - supply txid and True for non-verbose
|
||||||
assert_equal(self.nodes[0].getrawtransaction(txId, True)["hex"], rawTxSigned['hex'])
|
assert_equal(self.nodes[0].getrawtransaction(txId, True)["hex"], rawTxSigned['hex'])
|
||||||
|
assert_equal(self.nodes[0].getrawtransactionmulti({"0":[txId]}, True)[txId]['hex'], rawTxSigned['hex'])
|
||||||
|
|
||||||
# 6. invalid parameters - supply txid and string "Flase"
|
# 6. invalid parameters - supply txid and string "Flase"
|
||||||
assert_raises_rpc_error(-1, "not a boolean", self.nodes[0].getrawtransaction, txId, "Flase")
|
assert_raises_rpc_error(-1, "not a boolean", self.nodes[0].getrawtransaction, txId, "Flase")
|
||||||
|
Loading…
Reference in New Issue
Block a user