aboutsummaryrefslogtreecommitdiff
path: root/src/rpc
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@gmail.com>2016-04-15 16:36:39 +0200
committerWladimir J. van der Laan <laanwj@gmail.com>2016-04-15 16:43:21 +0200
commit9e47fcec1798e1db9a32ae243605e8245ffdb273 (patch)
tree233e8ae0b6d19e5e42b791b26bbc43c514f430c7 /src/rpc
parentbe14ca5e8c0f0e8cd8ef511ccb9c41f245d62fbf (diff)
parent509cb006d514cece5ab7680094f033c8dc8a2318 (diff)
downloadbitcoin-9e47fcec1798e1db9a32ae243605e8245ffdb273.tar.xz
Merge #7756: Add cursor to iterate over utxo set, use this in `gettxoutsetinfo`
509cb00 txdb: Add Cursor() method to CCoinsView to iterate over UTXO set (Wladimir J. van der Laan)
Diffstat (limited to 'src/rpc')
-rw-r--r--src/rpc/blockchain.cpp58
1 files changed, 57 insertions, 1 deletions
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 7a01a10b7d..b85b2f6b57 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -18,11 +18,14 @@
#include "txmempool.h"
#include "util.h"
#include "utilstrencodings.h"
+#include "hash.h"
#include <stdint.h>
#include <univalue.h>
+#include <boost/thread/thread.hpp> // boost::thread::interrupt
+
using namespace std;
extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry);
@@ -432,6 +435,59 @@ UniValue getblock(const UniValue& params, bool fHelp)
return blockToJSON(block, pblockindex);
}
+struct CCoinsStats
+{
+ int nHeight;
+ uint256 hashBlock;
+ uint64_t nTransactions;
+ uint64_t nTransactionOutputs;
+ uint64_t nSerializedSize;
+ uint256 hashSerialized;
+ CAmount nTotalAmount;
+
+ CCoinsStats() : nHeight(0), nTransactions(0), nTransactionOutputs(0), nSerializedSize(0), nTotalAmount(0) {}
+};
+
+//! Calculate statistics about the unspent transaction output set
+static bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats)
+{
+ boost::scoped_ptr<CCoinsViewCursor> pcursor(view->Cursor());
+
+ CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
+ stats.hashBlock = pcursor->GetBestBlock();
+ {
+ LOCK(cs_main);
+ stats.nHeight = mapBlockIndex.find(stats.hashBlock)->second->nHeight;
+ }
+ ss << stats.hashBlock;
+ CAmount nTotalAmount = 0;
+ while (pcursor->Valid()) {
+ boost::this_thread::interruption_point();
+ uint256 key;
+ CCoins coins;
+ if (pcursor->GetKey(key) && pcursor->GetValue(coins)) {
+ stats.nTransactions++;
+ for (unsigned int i=0; i<coins.vout.size(); i++) {
+ const CTxOut &out = coins.vout[i];
+ if (!out.IsNull()) {
+ stats.nTransactionOutputs++;
+ ss << VARINT(i+1);
+ ss << out;
+ nTotalAmount += out.nValue;
+ }
+ }
+ stats.nSerializedSize += 32 + pcursor->GetValueSize();
+ ss << VARINT(0);
+ } else {
+ return error("%s: unable to read value", __func__);
+ }
+ pcursor->Next();
+ }
+ stats.hashSerialized = ss.GetHash();
+ stats.nTotalAmount = nTotalAmount;
+ return true;
+}
+
UniValue gettxoutsetinfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
@@ -458,7 +514,7 @@ UniValue gettxoutsetinfo(const UniValue& params, bool fHelp)
CCoinsStats stats;
FlushStateToDisk();
- if (pcoinsTip->GetStats(stats)) {
+ if (GetUTXOStats(pcoinsTip, stats)) {
ret.push_back(Pair("height", (int64_t)stats.nHeight));
ret.push_back(Pair("bestblock", stats.hashBlock.GetHex()));
ret.push_back(Pair("transactions", (int64_t)stats.nTransactions));