Skip to content

Commit df254c3

Browse files
authored
Merge pull request #2205 from jamescowens/rpc_getblocksbatch
rpc: Implement getblocksbatch
2 parents 56e7928 + afad60e commit df254c3

File tree

4 files changed

+128
-0
lines changed

4 files changed

+128
-0
lines changed

src/rpc/blockchain.cpp

+124
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,130 @@ UniValue getblockbynumber(const UniValue& params, bool fHelp)
518518
return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
519519
}
520520

521+
UniValue getblocksbatch(const UniValue& params, bool fHelp)
522+
{
523+
g_timer.InitTimer(__func__, LogInstance().WillLogCategory(BCLog::LogFlags::RPC));
524+
525+
if (fHelp || params.size() < 2 || params.size() > 3)
526+
{
527+
throw runtime_error(
528+
"getblocksbatch <starting block number or hash> <number of blocks> [bool:txinfo]\n"
529+
"\n"
530+
"<starting block number or hash> the block number or hash for the block at the\n"
531+
"start of the batch\n"
532+
"\n"
533+
"<number of blocks> the number of blocks to return in the batch, limited to 1000"
534+
"\n"
535+
"[bool:txinfo] optional to print more detailed tx info\n"
536+
"\n"
537+
"Returns a JSON array with details of the requested blocks starting with\n"
538+
"the given block-number or hash.\n");
539+
}
540+
541+
UniValue result(UniValue::VOBJ);
542+
UniValue blocks(UniValue::VARR);
543+
544+
int nHeight = 0;
545+
uint256 hash;
546+
bool block_hash_provided = false;
547+
548+
// Validate parameters.
549+
try
550+
{
551+
// Have to do it this way, because the rpc param 0 must be left out of the special parameter handling in client.cpp.
552+
nHeight = boost::lexical_cast<int>(params[0].get_str());
553+
}
554+
catch (const boost::bad_lexical_cast& e)
555+
{
556+
std::string strHash = params[0].get_str();
557+
hash = uint256S(strHash);
558+
block_hash_provided = true;
559+
}
560+
catch (...)
561+
{
562+
throw JSONRPCError(RPC_INVALID_PARAMETER, "Either a valid block number or block hash must be provided.");
563+
}
564+
565+
if (!block_hash_provided)
566+
{
567+
if (nHeight < 0 || nHeight > nBestHeight)
568+
{
569+
throw JSONRPCError(RPC_INVALID_PARAMETER, "Starting block number out of range");
570+
}
571+
}
572+
else
573+
{
574+
if (mapBlockIndex.count(hash) == 0)
575+
{
576+
throw JSONRPCError(RPC_INVALID_PARAMETER, "Starting block for batch not found.");
577+
}
578+
}
579+
580+
int batch_size = params[1].get_int();
581+
if (batch_size < 1 || batch_size > 1000)
582+
{
583+
throw JSONRPCError(RPC_INVALID_PARAMETER, "Batch size must be between 1 and 1000, inclusive.");
584+
}
585+
586+
bool transaction_details = false;
587+
if (params.size() > 2) transaction_details = params[2].get_bool();
588+
589+
LOCK(cs_main);
590+
591+
g_timer.GetTimes("Finished validating parameters", __func__);
592+
593+
CBlockIndex* pblockindex_head = nullptr;
594+
CBlockIndex* pblockindex = nullptr;
595+
596+
// Find the starting block's index entry point by either rewinding from the head (if the block number was
597+
// provided), or directly from the mapBlockIndex, if the hash was provided.
598+
599+
// Select the block index for the head of the chain.
600+
pblockindex_head = mapBlockIndex[hashBestChain];
601+
602+
if (!block_hash_provided)
603+
{
604+
pblockindex = pblockindex_head;
605+
606+
// Rewind to the block corresponding to the specified height.
607+
while (pblockindex->nHeight > nHeight)
608+
{
609+
pblockindex = pblockindex->pprev;
610+
}
611+
612+
}
613+
else
614+
{
615+
pblockindex = mapBlockIndex[hash];
616+
}
617+
618+
g_timer.GetTimes("Finished finding starting block", __func__);
619+
620+
int i = 0;
621+
while (i < batch_size)
622+
{
623+
CBlock block;
624+
if (!block.ReadFromDisk(pblockindex, true))
625+
{
626+
throw runtime_error("Error reading block from specified batch.");
627+
}
628+
629+
blocks.push_back(blockToJSON(block, pblockindex, transaction_details));
630+
++i;
631+
632+
if (pblockindex == pblockindex_head) break;
633+
634+
pblockindex = pblockindex->pnext;
635+
}
636+
637+
result.pushKV("block_count", i);
638+
result.pushKV("blocks", blocks);
639+
640+
g_timer.GetTimes("Finished populating result for block batch", __func__);
641+
642+
return result;
643+
}
644+
521645
UniValue backupprivatekeys(const UniValue& params, bool fHelp)
522646
{
523647
if (fHelp || params.size() != 0)

src/rpc/client.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
199199
{ "getblock" , 1 },
200200
{ "getblockbynumber" , 0 },
201201
{ "getblockbynumber" , 1 },
202+
{ "getblocksbatch" , 1 },
203+
{ "getblocksbatch" , 2 },
202204
{ "getblockhash" , 0 },
203205
{ "setban" , 2 },
204206
{ "setban" , 3 },

src/rpc/server.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,7 @@ static const CRPCCommand vRPCCommands[] =
415415
{ "getbestblockhash", &getbestblockhash, cat_network },
416416
{ "getblock", &getblock, cat_network },
417417
{ "getblockbynumber", &getblockbynumber, cat_network },
418+
{ "getblocksbatch", &getblocksbatch, cat_network },
418419
{ "getblockcount", &getblockcount, cat_network },
419420
{ "getblockhash", &getblockhash, cat_network },
420421
{ "getburnreport", &getburnreport, cat_network },

src/rpc/server.h

+1
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ extern UniValue getaddednodeinfo(const UniValue& params, bool fHelp);
228228
extern UniValue getbestblockhash(const UniValue& params, bool fHelp);
229229
extern UniValue getblock(const UniValue& params, bool fHelp);
230230
extern UniValue getblockbynumber(const UniValue& params, bool fHelp);
231+
extern UniValue getblocksbatch(const UniValue& params, bool fHelp);
231232
extern UniValue getblockchaininfo(const UniValue& params, bool fHelp);
232233
extern UniValue getblockcount(const UniValue& params, bool fHelp);
233234
extern UniValue getblockhash(const UniValue& params, bool fHelp);

0 commit comments

Comments
 (0)