getblocktemplate: longpolling support

This commit is contained in:
Luke Dashjr
2012-05-13 04:43:24 +00:00
committed by Wladimir J. van der Laan
parent f0fc81a083
commit ff6a7af154
6 changed files with 82 additions and 1 deletions

View File

@@ -324,6 +324,7 @@ Value getblocktemplate(const Array& params, bool fHelp)
);
std::string strMode = "template";
Value lpval = Value::null;
if (params.size() > 0)
{
const Object& oparam = params[0].get_obj();
@@ -336,6 +337,7 @@ Value getblocktemplate(const Array& params, bool fHelp)
}
else
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode");
lpval = find_value(oparam, "longpollid");
}
if (strMode != "template")
@@ -347,8 +349,63 @@ Value getblocktemplate(const Array& params, bool fHelp)
if (IsInitialBlockDownload())
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Bitcoin is downloading blocks...");
// Update block
static unsigned int nTransactionsUpdatedLast;
if (lpval.type() != null_type)
{
// Wait to respond until either the best block changes, OR a minute has passed and there are more transactions
uint256 hashWatchedChain;
boost::system_time checktxtime;
unsigned int nTransactionsUpdatedLastLP;
if (lpval.type() == str_type)
{
// Format: <hashBestChain><nTransactionsUpdatedLast>
std::string lpstr = lpval.get_str();
hashWatchedChain.SetHex(lpstr.substr(0, 64));
nTransactionsUpdatedLastLP = atoi64(lpstr.substr(64));
}
else
{
// NOTE: Spec does not specify behaviour for non-string longpollid, but this makes testing easier
hashWatchedChain = chainActive.Tip()->GetBlockHash();
nTransactionsUpdatedLastLP = nTransactionsUpdatedLast;
}
// Release the wallet and main lock while waiting
#ifdef ENABLE_WALLET
if(pwalletMain)
LEAVE_CRITICAL_SECTION(pwalletMain->cs_wallet);
#endif
LEAVE_CRITICAL_SECTION(cs_main);
{
checktxtime = boost::get_system_time() + boost::posix_time::minutes(1);
boost::unique_lock<boost::mutex> lock(csBestBlock);
while (chainActive.Tip()->GetBlockHash() == hashWatchedChain && IsRPCRunning())
{
if (!cvBlockChange.timed_wait(lock, checktxtime))
{
// Timeout: Check transactions for update
if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLastLP)
break;
checktxtime += boost::posix_time::seconds(10);
}
}
}
ENTER_CRITICAL_SECTION(cs_main);
#ifdef ENABLE_WALLET
if(pwalletMain)
ENTER_CRITICAL_SECTION(pwalletMain->cs_wallet);
#endif
if (!IsRPCRunning())
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Shutting down");
// TODO: Maybe recheck connections/IBD and (if something wrong) send an expires-immediately template to stop miners?
}
// Update block
static CBlockIndex* pindexPrev;
static int64_t nStart;
static CBlockTemplate* pblocktemplate;
@@ -436,6 +493,7 @@ Value getblocktemplate(const Array& params, bool fHelp)
result.push_back(Pair("transactions", transactions));
result.push_back(Pair("coinbaseaux", aux));
result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
result.push_back(Pair("longpollid", chainActive.Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast)));
result.push_back(Pair("target", hashTarget.GetHex()));
result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
result.push_back(Pair("mutable", aMutable));