aboutsummaryrefslogtreecommitdiff
path: root/src/rpc/blockchain.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/rpc/blockchain.cpp')
-rw-r--r--src/rpc/blockchain.cpp207
1 files changed, 176 insertions, 31 deletions
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 675d9ba904..1e04fcc01c 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -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);
@@ -101,7 +113,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
result.push_back(Pair("confirmations", confirmations));
result.push_back(Pair("strippedsize", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS)));
result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
- result.push_back(Pair("cost", (int)::GetBlockCost(block)));
+ result.push_back(Pair("weight", (int)::GetBlockWeight(block)));
result.push_back(Pair("height", blockindex->nHeight));
result.push_back(Pair("version", block.nVersion));
result.push_back(Pair("versionHex", strprintf("%08x", block.nVersion)));
@@ -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)
@@ -353,10 +497,10 @@ UniValue getmempoolancestors(const UniValue& params, bool fHelp)
UniValue o(UniValue::VOBJ);
BOOST_FOREACH(CTxMemPool::txiter ancestorIt, setAncestors) {
const CTxMemPoolEntry &e = *ancestorIt;
- const uint256& hash = e.GetTx().GetHash();
+ const uint256& _hash = e.GetTx().GetHash();
UniValue info(UniValue::VOBJ);
entryToJSON(info, e);
- o.push_back(Pair(hash.ToString(), info));
+ o.push_back(Pair(_hash.ToString(), info));
}
return o;
}
@@ -417,10 +561,10 @@ UniValue getmempooldescendants(const UniValue& params, bool fHelp)
UniValue o(UniValue::VOBJ);
BOOST_FOREACH(CTxMemPool::txiter descendantIt, setDescendants) {
const CTxMemPoolEntry &e = *descendantIt;
- const uint256& hash = e.GetTx().GetHash();
+ const uint256& _hash = e.GetTx().GetHash();
UniValue info(UniValue::VOBJ);
entryToJSON(info, e);
- o.push_back(Pair(hash.ToString(), info));
+ o.push_back(Pair(_hash.ToString(), info));
}
return o;
}
@@ -559,7 +703,7 @@ UniValue getblock(const UniValue& params, bool fHelp)
" \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n"
" \"size\" : n, (numeric) The block size\n"
" \"strippedsize\" : n, (numeric) The block size excluding witness data\n"
- " \"cost\" : n (numeric) The block cost\n"
+ " \"weight\" : n (numeric) The block weight (BIP 141)\n"
" \"height\" : n, (numeric) The block height or index\n"
" \"version\" : n, (numeric) The block version\n"
" \"versionHex\" : \"00000000\", (string) The block version formatted in hexadecimal\n"
@@ -632,7 +776,7 @@ struct CCoinsStats
//! Calculate statistics about the unspent transaction output set
static bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats)
{
- boost::scoped_ptr<CCoinsViewCursor> pcursor(view->Cursor());
+ std::unique_ptr<CCoinsViewCursor> pcursor(view->Cursor());
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
stats.hashBlock = pcursor->GetBestBlock();
@@ -704,6 +848,8 @@ UniValue gettxoutsetinfo(const UniValue& params, bool fHelp)
ret.push_back(Pair("bytes_serialized", (int64_t)stats.nSerializedSize));
ret.push_back(Pair("hash_serialized", stats.hashSerialized.GetHex()));
ret.push_back(Pair("total_amount", ValueFromAmount(stats.nTotalAmount)));
+ } else {
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
}
return ret;
}
@@ -817,22 +963,23 @@ UniValue verifychain(const UniValue& params, bool fHelp)
}
/** Implementation of IsSuperMajority with better feedback */
-static UniValue SoftForkMajorityDesc(int minVersion, CBlockIndex* pindex, int nRequired, const Consensus::Params& consensusParams)
+static UniValue SoftForkMajorityDesc(int version, CBlockIndex* pindex, const Consensus::Params& consensusParams)
{
- int nFound = 0;
- CBlockIndex* pstart = pindex;
- for (int i = 0; i < consensusParams.nMajorityWindow && pstart != NULL; i++)
+ UniValue rv(UniValue::VOBJ);
+ bool activated = false;
+ switch(version)
{
- if (pstart->nVersion >= minVersion)
- ++nFound;
- pstart = pstart->pprev;
+ case 2:
+ activated = pindex->nHeight >= consensusParams.BIP34Height;
+ break;
+ case 3:
+ activated = pindex->nHeight >= consensusParams.BIP66Height;
+ break;
+ case 4:
+ activated = pindex->nHeight >= consensusParams.BIP65Height;
+ break;
}
-
- UniValue rv(UniValue::VOBJ);
- rv.push_back(Pair("status", nFound >= nRequired));
- rv.push_back(Pair("found", nFound));
- rv.push_back(Pair("required", nRequired));
- rv.push_back(Pair("window", consensusParams.nMajorityWindow));
+ rv.push_back(Pair("status", activated));
return rv;
}
@@ -841,8 +988,7 @@ static UniValue SoftForkDesc(const std::string &name, int version, CBlockIndex*
UniValue rv(UniValue::VOBJ);
rv.push_back(Pair("id", name));
rv.push_back(Pair("version", version));
- rv.push_back(Pair("enforce", SoftForkMajorityDesc(version, pindex, consensusParams.nMajorityEnforceBlockUpgrade, consensusParams)));
- rv.push_back(Pair("reject", SoftForkMajorityDesc(version, pindex, consensusParams.nMajorityRejectBlockOutdated, consensusParams)));
+ rv.push_back(Pair("reject", SoftForkMajorityDesc(version, pindex, consensusParams)));
return rv;
}
@@ -897,13 +1043,9 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
" {\n"
" \"id\": \"xxxx\", (string) name of softfork\n"
" \"version\": xx, (numeric) block version\n"
- " \"enforce\": { (object) progress toward enforcing the softfork rules for new-version blocks\n"
+ " \"reject\": { (object) progress toward rejecting pre-softfork blocks\n"
" \"status\": xx, (boolean) true if threshold reached\n"
- " \"found\": xx, (numeric) number of blocks with the new version found\n"
- " \"required\": xx, (numeric) number of blocks required to trigger\n"
- " \"window\": xx, (numeric) maximum size of examined window of recent blocks\n"
" },\n"
- " \"reject\": { ... } (object) progress toward rejecting pre-softfork blocks (same fields as \"enforce\")\n"
" }, ...\n"
" ],\n"
" \"bip9_softforks\": { (object) status of BIP9 softforks in progress\n"
@@ -1137,7 +1279,7 @@ UniValue invalidateblock(const UniValue& params, bool fHelp)
}
if (state.IsValid()) {
- ActivateBestChain(state, Params());
+ ActivateBestChain(state, Params(), NULL, g_connman.get());
}
if (!state.IsValid()) {
@@ -1175,7 +1317,7 @@ UniValue reconsiderblock(const UniValue& params, bool fHelp)
}
CValidationState state;
- ActivateBestChain(state, Params());
+ ActivateBestChain(state, Params(), NULL, g_connman.get());
if (!state.IsValid()) {
throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());
@@ -1207,10 +1349,13 @@ 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 &tableRPC)
+void RegisterBlockchainRPCCommands(CRPCTable &t)
{
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
- tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
+ t.appendCommand(commands[vcidx].name, &commands[vcidx]);
}