mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-03-16 10:30:41 +01:00
add waitfornewblock/waitforblock/waitforblockheight rpcs and use them for tests
waitfornewblock waits until a new block is received, or the timeout expires, then returns the current block height/hash. waitforblock waits for a specific blockhash, or until the timeout expires, then returns the current block height/hash. If the target blockhash is the current tip, it will return immediately. waitforblockheight waits until the tip has reached a certain height or higher, then returns the current height and hash. waitforblockheight is used to avoid polling in the rpc tests.
This commit is contained in:
@@ -26,8 +26,20 @@
|
||||
|
||||
#include <boost/thread/thread.hpp> // boost::thread::interrupt
|
||||
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
using namespace std;
|
||||
|
||||
struct CUpdatedBlock
|
||||
{
|
||||
uint256 hash;
|
||||
int height;
|
||||
};
|
||||
|
||||
static std::mutex cs_blockchange;
|
||||
static std::condition_variable cond_blockchange;
|
||||
static CUpdatedBlock latestblock;
|
||||
|
||||
extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry);
|
||||
void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);
|
||||
|
||||
@@ -168,6 +180,138 @@ UniValue getbestblockhash(const UniValue& params, bool fHelp)
|
||||
return chainActive.Tip()->GetBlockHash().GetHex();
|
||||
}
|
||||
|
||||
void RPCNotifyBlockChange(bool ibd, const CBlockIndex * pindex)
|
||||
{
|
||||
if(pindex) {
|
||||
std::lock_guard<std::mutex> lock(cs_blockchange);
|
||||
latestblock.hash = pindex->GetBlockHash();
|
||||
latestblock.height = pindex->nHeight;
|
||||
}
|
||||
cond_blockchange.notify_all();
|
||||
}
|
||||
|
||||
UniValue waitfornewblock(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() > 1)
|
||||
throw runtime_error(
|
||||
"waitfornewblock\n"
|
||||
"\nWaits for a specific new block and returns useful info about it.\n"
|
||||
"\nReturns the current block on timeout or exit.\n"
|
||||
"\nArguments:\n"
|
||||
"1. timeout (milliseconds) (int, optional, default=false)\n"
|
||||
"\nResult::\n"
|
||||
"{ (json object)\n"
|
||||
" \"hash\" : { (string) The blockhash\n"
|
||||
" \"height\" : { (int) Block height\n"
|
||||
"}\n"
|
||||
"\nExamples\n"
|
||||
+ HelpExampleCli("waitfornewblock", "1000")
|
||||
+ HelpExampleRpc("waitfornewblock", "1000")
|
||||
);
|
||||
int timeout = 0;
|
||||
if (params.size() > 0)
|
||||
timeout = params[0].get_int();
|
||||
|
||||
CUpdatedBlock block;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(cs_blockchange);
|
||||
block = latestblock;
|
||||
if(timeout)
|
||||
cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&block]{return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); });
|
||||
else
|
||||
cond_blockchange.wait(lock, [&block]{return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); });
|
||||
block = latestblock;
|
||||
}
|
||||
UniValue ret(UniValue::VOBJ);
|
||||
ret.push_back(Pair("hash", block.hash.GetHex()));
|
||||
ret.push_back(Pair("height", block.height));
|
||||
return ret;
|
||||
}
|
||||
|
||||
UniValue waitforblock(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() < 1 || params.size() > 2)
|
||||
throw runtime_error(
|
||||
"waitforblock\n"
|
||||
"\nWaits for a specific new block and returns useful info about it.\n"
|
||||
"\nReturns the current block on timeout or exit.\n"
|
||||
"\nArguments:\n"
|
||||
"1. blockhash to wait for (string)\n"
|
||||
"2. timeout (milliseconds) (int, optional, default=false)\n"
|
||||
"\nResult::\n"
|
||||
"{ (json object)\n"
|
||||
" \"hash\" : { (string) The blockhash\n"
|
||||
" \"height\" : { (int) Block height\n"
|
||||
"}\n"
|
||||
"\nExamples\n"
|
||||
+ HelpExampleCli("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000")
|
||||
+ HelpExampleRpc("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000")
|
||||
);
|
||||
int timeout = 0;
|
||||
|
||||
uint256 hash = uint256S(params[0].get_str());
|
||||
|
||||
if (params.size() > 1)
|
||||
timeout = params[1].get_int();
|
||||
|
||||
CUpdatedBlock block;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(cs_blockchange);
|
||||
if(timeout)
|
||||
cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&hash]{return latestblock.hash == hash || !IsRPCRunning();});
|
||||
else
|
||||
cond_blockchange.wait(lock, [&hash]{return latestblock.hash == hash || !IsRPCRunning(); });
|
||||
block = latestblock;
|
||||
}
|
||||
|
||||
UniValue ret(UniValue::VOBJ);
|
||||
ret.push_back(Pair("hash", block.hash.GetHex()));
|
||||
ret.push_back(Pair("height", block.height));
|
||||
return ret;
|
||||
}
|
||||
|
||||
UniValue waitforblockheight(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() < 1 || params.size() > 2)
|
||||
throw runtime_error(
|
||||
"waitforblock\n"
|
||||
"\nWaits for (at least) block height and returns the height and hash\n"
|
||||
"\nof the current tip.\n"
|
||||
"\nReturns the current block on timeout or exit.\n"
|
||||
"\nArguments:\n"
|
||||
"1. block height to wait for (int)\n"
|
||||
"2. timeout (milliseconds) (int, optional, default=false)\n"
|
||||
"\nResult::\n"
|
||||
"{ (json object)\n"
|
||||
" \"hash\" : { (string) The blockhash\n"
|
||||
" \"height\" : { (int) Block height\n"
|
||||
"}\n"
|
||||
"\nExamples\n"
|
||||
+ HelpExampleCli("waitforblockheight", "\"100\", 1000")
|
||||
+ HelpExampleRpc("waitforblockheight", "\"100\", 1000")
|
||||
);
|
||||
int timeout = 0;
|
||||
|
||||
int height = params[0].get_int();
|
||||
|
||||
if (params.size() > 1)
|
||||
timeout = params[1].get_int();
|
||||
|
||||
CUpdatedBlock block;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(cs_blockchange);
|
||||
if(timeout)
|
||||
cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&height]{return latestblock.height >= height || !IsRPCRunning();});
|
||||
else
|
||||
cond_blockchange.wait(lock, [&height]{return latestblock.height >= height || !IsRPCRunning(); });
|
||||
block = latestblock;
|
||||
}
|
||||
UniValue ret(UniValue::VOBJ);
|
||||
ret.push_back(Pair("hash", block.hash.GetHex()));
|
||||
ret.push_back(Pair("height", block.height));
|
||||
return ret;
|
||||
}
|
||||
|
||||
UniValue getdifficulty(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() != 0)
|
||||
@@ -1203,6 +1347,9 @@ static const CRPCCommand commands[] =
|
||||
/* Not shown in help */
|
||||
{ "hidden", "invalidateblock", &invalidateblock, true },
|
||||
{ "hidden", "reconsiderblock", &reconsiderblock, true },
|
||||
{ "hidden", "waitfornewblock", &waitfornewblock, true },
|
||||
{ "hidden", "waitforblock", &waitforblock, true },
|
||||
{ "hidden", "waitforblockheight", &waitforblockheight, true },
|
||||
};
|
||||
|
||||
void RegisterBlockchainRPCCommands(CRPCTable &t)
|
||||
|
||||
Reference in New Issue
Block a user