mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 12:02:48 +01:00
Merge #8680: Address Travis spurious failures
d6a5dc4
add waitfornewblock/waitforblock/waitforblockheight rpcs and use them for tests (Cory Fields)
This commit is contained in:
parent
6924212f09
commit
c2a601f507
@ -135,12 +135,16 @@ def sync_blocks(rpc_connections, wait=1, timeout=60):
|
|||||||
"""
|
"""
|
||||||
Wait until everybody has the same tip
|
Wait until everybody has the same tip
|
||||||
"""
|
"""
|
||||||
|
maxheight = 0
|
||||||
while timeout > 0:
|
while timeout > 0:
|
||||||
tips = [ x.getbestblockhash() for x in rpc_connections ]
|
tips = [ x.waitforblockheight(maxheight, int(wait * 1000)) for x in rpc_connections ]
|
||||||
|
heights = [ x["height"] for x in tips ]
|
||||||
if tips == [ tips[0] ]*len(tips):
|
if tips == [ tips[0] ]*len(tips):
|
||||||
return True
|
return True
|
||||||
time.sleep(wait)
|
if heights == [ heights[0] ]*len(heights): #heights are the same but hashes are not
|
||||||
|
raise AssertionError("Block sync failed")
|
||||||
timeout -= wait
|
timeout -= wait
|
||||||
|
maxheight = max(heights)
|
||||||
raise AssertionError("Block sync failed")
|
raise AssertionError("Block sync failed")
|
||||||
|
|
||||||
def sync_mempools(rpc_connections, wait=1, timeout=60):
|
def sync_mempools(rpc_connections, wait=1, timeout=60):
|
||||||
|
@ -355,9 +355,15 @@ bool static Bind(CConnman& connman, const CService &addr, unsigned int flags) {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
void OnRPCStarted()
|
||||||
|
{
|
||||||
|
uiInterface.NotifyBlockTip.connect(&RPCNotifyBlockChange);
|
||||||
|
}
|
||||||
|
|
||||||
void OnRPCStopped()
|
void OnRPCStopped()
|
||||||
{
|
{
|
||||||
|
uiInterface.NotifyBlockTip.disconnect(&RPCNotifyBlockChange);
|
||||||
|
RPCNotifyBlockChange(false, nullptr);
|
||||||
cvBlockChange.notify_all();
|
cvBlockChange.notify_all();
|
||||||
LogPrint("rpc", "RPC stopped.\n");
|
LogPrint("rpc", "RPC stopped.\n");
|
||||||
}
|
}
|
||||||
@ -774,6 +780,7 @@ bool InitSanityCheck(void)
|
|||||||
|
|
||||||
bool AppInitServers(boost::thread_group& threadGroup)
|
bool AppInitServers(boost::thread_group& threadGroup)
|
||||||
{
|
{
|
||||||
|
RPCServer::OnStarted(&OnRPCStarted);
|
||||||
RPCServer::OnStopped(&OnRPCStopped);
|
RPCServer::OnStopped(&OnRPCStopped);
|
||||||
RPCServer::OnPreCommand(&OnRPCPreCommand);
|
RPCServer::OnPreCommand(&OnRPCPreCommand);
|
||||||
if (!InitHTTPServer())
|
if (!InitHTTPServer())
|
||||||
@ -1554,6 +1561,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
|||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
CBlockIndex* tip = chainActive.Tip();
|
CBlockIndex* tip = chainActive.Tip();
|
||||||
|
RPCNotifyBlockChange(true, tip);
|
||||||
if (tip && tip->nTime > GetAdjustedTime() + 2 * 60 * 60) {
|
if (tip && tip->nTime > GetAdjustedTime() + 2 * 60 * 60) {
|
||||||
strLoadError = _("The block database contains a block which appears to be from the future. "
|
strLoadError = _("The block database contains a block which appears to be from the future. "
|
||||||
"This may be due to your computer's date and time being set incorrectly. "
|
"This may be due to your computer's date and time being set incorrectly. "
|
||||||
|
@ -28,8 +28,20 @@
|
|||||||
|
|
||||||
#include <boost/thread/thread.hpp> // boost::thread::interrupt
|
#include <boost/thread/thread.hpp> // boost::thread::interrupt
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <condition_variable>
|
||||||
using namespace std;
|
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);
|
extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry);
|
||||||
void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);
|
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();
|
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)
|
UniValue getdifficulty(const UniValue& params, bool fHelp)
|
||||||
{
|
{
|
||||||
if (fHelp || params.size() != 0)
|
if (fHelp || params.size() != 0)
|
||||||
@ -1364,6 +1508,9 @@ static const CRPCCommand commands[] =
|
|||||||
/* Not shown in help */
|
/* Not shown in help */
|
||||||
{ "hidden", "invalidateblock", &invalidateblock, true },
|
{ "hidden", "invalidateblock", &invalidateblock, true },
|
||||||
{ "hidden", "reconsiderblock", &reconsiderblock, true },
|
{ "hidden", "reconsiderblock", &reconsiderblock, true },
|
||||||
|
{ "hidden", "waitfornewblock", &waitfornewblock, true },
|
||||||
|
{ "hidden", "waitforblock", &waitforblock, true },
|
||||||
|
{ "hidden", "waitforblockheight", &waitforblockheight, true },
|
||||||
};
|
};
|
||||||
|
|
||||||
void RegisterBlockchainRPCCommands(CRPCTable &t)
|
void RegisterBlockchainRPCCommands(CRPCTable &t)
|
||||||
|
@ -58,6 +58,12 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
|||||||
{ "getchaintips", 1 },
|
{ "getchaintips", 1 },
|
||||||
{ "getblockhash", 0 },
|
{ "getblockhash", 0 },
|
||||||
{ "getsuperblockbudget", 0 },
|
{ "getsuperblockbudget", 0 },
|
||||||
|
{ "waitforblockheight", 0 },
|
||||||
|
{ "waitforblockheight", 1 },
|
||||||
|
{ "waitforblock", 1 },
|
||||||
|
{ "waitforblock", 2 },
|
||||||
|
{ "waitfornewblock", 0 },
|
||||||
|
{ "waitfornewblock", 1 },
|
||||||
{ "move", 2 },
|
{ "move", 2 },
|
||||||
{ "move", 3 },
|
{ "move", 3 },
|
||||||
{ "sendfrom", 2 },
|
{ "sendfrom", 2 },
|
||||||
|
@ -193,5 +193,6 @@ bool StartRPC();
|
|||||||
void InterruptRPC();
|
void InterruptRPC();
|
||||||
void StopRPC();
|
void StopRPC();
|
||||||
std::string JSONRPCExecBatch(const UniValue& vReq);
|
std::string JSONRPCExecBatch(const UniValue& vReq);
|
||||||
|
void RPCNotifyBlockChange(bool ibd, const CBlockIndex *);
|
||||||
|
|
||||||
#endif // BITCOIN_RPCSERVER_H
|
#endif // BITCOIN_RPCSERVER_H
|
||||||
|
Loading…
Reference in New Issue
Block a user