aboutsummaryrefslogtreecommitdiff
path: root/src/rpcmining.cpp
diff options
context:
space:
mode:
authorLuke Dashjr <luke-jr+git@utopios.org>2012-05-13 04:43:24 +0000
committerWladimir J. van der Laan <laanwj@gmail.com>2014-07-11 14:48:02 +0200
commitff6a7af154f2151c93a06b7ee86c167603c5ac55 (patch)
tree5042feb9576de0a4857ac41e444774a87f79194f /src/rpcmining.cpp
parentf0fc81a0832a8fa93c5d7e619e25f739d72b49f3 (diff)
getblocktemplate: longpolling support
Diffstat (limited to 'src/rpcmining.cpp')
-rw-r--r--src/rpcmining.cpp60
1 files changed, 59 insertions, 1 deletions
diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp
index c7621dc137..6f72ea7404 100644
--- a/src/rpcmining.cpp
+++ b/src/rpcmining.cpp
@@ -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));