aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPieter Wuille <pieter.wuille@gmail.com>2012-09-25 23:04:54 +0200
committerPieter Wuille <pieter.wuille@gmail.com>2012-10-20 23:08:57 +0200
commitbeeb57610cf57c1d802be993ac0e98211bfc5f0c (patch)
treeadf8ec903008407b95da0467a0ea8fcbf4909938
parente1bfbab8029c33102889d7d970da5b6cc32ff75b (diff)
Add gettxout and gettxoutsetinfo RPCs
-rw-r--r--src/bitcoinrpc.cpp4
-rw-r--r--src/bitcoinrpc.h2
-rw-r--r--src/main.cpp2
-rw-r--r--src/main.h12
-rw-r--r--src/rpcblockchain.cpp62
-rw-r--r--src/txdb-leveldb.cpp35
-rw-r--r--src/txdb-leveldb.h1
7 files changed, 118 insertions, 0 deletions
diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp
index 829c8ee2d7..725037addc 100644
--- a/src/bitcoinrpc.cpp
+++ b/src/bitcoinrpc.cpp
@@ -256,6 +256,8 @@ static const CRPCCommand vRPCCommands[] =
{ "decoderawtransaction", &decoderawtransaction, false, false },
{ "signrawtransaction", &signrawtransaction, false, false },
{ "sendrawtransaction", &sendrawtransaction, false, false },
+ { "gettxoutsetinfo", &gettxoutsetinfo, true, false },
+ { "gettxout", &gettxout, true, false },
};
CRPCTable::CRPCTable()
@@ -1166,6 +1168,8 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri
if (strMethod == "createrawtransaction" && n > 1) ConvertTo<Object>(params[1]);
if (strMethod == "signrawtransaction" && n > 1) ConvertTo<Array>(params[1], true);
if (strMethod == "signrawtransaction" && n > 2) ConvertTo<Array>(params[2], true);
+ if (strMethod == "gettxout" && n > 1) ConvertTo<boost::int64_t>(params[1]);
+ if (strMethod == "gettxout" && n > 2) ConvertTo<bool>(params[2]);
return params;
}
diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h
index 89ab976f56..9290697664 100644
--- a/src/bitcoinrpc.h
+++ b/src/bitcoinrpc.h
@@ -187,5 +187,7 @@ extern json_spirit::Value settxfee(const json_spirit::Array& params, bool fHelp)
extern json_spirit::Value getrawmempool(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getblockhash(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getblock(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value gettxoutsetinfo(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value gettxout(const json_spirit::Array& params, bool fHelp);
#endif
diff --git a/src/main.cpp b/src/main.cpp
index 94f1a93151..064ac7e10d 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -171,6 +171,7 @@ bool CCoinsView::HaveCoins(uint256 txid) { return false; }
CBlockIndex *CCoinsView::GetBestBlock() { return NULL; }
bool CCoinsView::SetBestBlock(CBlockIndex *pindex) { return false; }
bool CCoinsView::BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex) { return false; }
+bool CCoinsView::GetStats(CCoinsStats &stats) { return false; }
CCoinsViewBacked::CCoinsViewBacked(CCoinsView &viewIn) : base(&viewIn) { }
@@ -181,6 +182,7 @@ CBlockIndex *CCoinsViewBacked::GetBestBlock() { return base->GetBestBlock(); }
bool CCoinsViewBacked::SetBestBlock(CBlockIndex *pindex) { return base->SetBestBlock(pindex); }
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
bool CCoinsViewBacked::BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex) { return base->BatchWrite(mapCoins, pindex); }
+bool CCoinsViewBacked::GetStats(CCoinsStats &stats) { return base->GetStats(stats); }
CCoinsViewCache::CCoinsViewCache(CCoinsView &baseIn, bool fDummy) : CCoinsViewBacked(baseIn), pindexTip(NULL) { }
diff --git a/src/main.h b/src/main.h
index 1126feb09b..75ee7a9be5 100644
--- a/src/main.h
+++ b/src/main.h
@@ -1791,6 +1791,16 @@ public:
extern CTxMemPool mempool;
+struct CCoinsStats
+{
+ int nHeight;
+ uint64 nTransactions;
+ uint64 nTransactionOutputs;
+ uint64 nSerializedSize;
+
+ CCoinsStats() : nHeight(0), nTransactions(0), nTransactionOutputs(0), nSerializedSize(0) {}
+};
+
/** Abstract view on the open txout dataset. */
class CCoinsView
{
@@ -1811,6 +1821,7 @@ public:
// Modify the currently active block index
virtual bool SetBestBlock(CBlockIndex *pindex);
virtual bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
+ virtual bool GetStats(CCoinsStats &stats);
};
/** CCoinsView backed by another CCoinsView */
@@ -1828,6 +1839,7 @@ public:
bool SetBestBlock(CBlockIndex *pindex);
void SetBackend(CCoinsView &viewIn);
bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
+ bool GetStats(CCoinsStats &stats);
};
/** CCoinsView that adds a memory cache for transactions to another CCoinsView */
diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp
index 2dfdf58422..3fde463cd3 100644
--- a/src/rpcblockchain.cpp
+++ b/src/rpcblockchain.cpp
@@ -159,7 +159,69 @@ Value getblock(const Array& params, bool fHelp)
return blockToJSON(block, pblockindex);
}
+Value gettxoutsetinfo(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() != 0)
+ throw runtime_error(
+ "gettxoutsetinfo\n"
+ "Returns statistics about the unspent transaction output set.");
+
+ Object ret;
+
+ CCoinsStats stats;
+ if (pcoinsTip->GetStats(stats)) {
+ ret.push_back(Pair("bestblock", pcoinsTip->GetBestBlock()->GetBlockHash().GetHex()));
+ ret.push_back(Pair("transactions", (boost::int64_t)stats.nTransactions));
+ ret.push_back(Pair("txouts", (boost::int64_t)stats.nTransactionOutputs));
+ ret.push_back(Pair("bytes_serialized", (boost::int64_t)stats.nSerializedSize));
+ }
+ return ret;
+}
+Value gettxout(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() < 2 || params.size() > 3)
+ throw runtime_error(
+ "gettxout <txid> <n> [includemempool=true]\n"
+ "Returns details about an unspent transaction output.");
+ Object ret;
+
+ std::string strHash = params[0].get_str();
+ uint256 hash(strHash);
+ int n = params[1].get_int();
+ bool fMempool = true;
+ if (params.size() > 2)
+ fMempool = params[2].get_bool();
+
+ CCoins coins;
+ if (fMempool) {
+ LOCK(mempool.cs);
+ CCoinsViewMemPool view(*pcoinsTip, mempool);
+ if (!view.GetCoins(hash, coins))
+ return Value::null;
+ mempool.pruneSpent(hash, coins); // TODO: this should be done by the CCoinsViewMemPool
+ } else {
+ if (!pcoinsTip->GetCoins(hash, coins))
+ return Value::null;
+ }
+ if (n<0 || (unsigned int)n>=coins.vout.size() || coins.vout[n].IsNull())
+ return Value::null;
+
+ ret.push_back(Pair("bestblock", pcoinsTip->GetBestBlock()->GetBlockHash().GetHex()));
+ if ((unsigned int)coins.nHeight == MEMPOOL_HEIGHT)
+ ret.push_back(Pair("confirmations", 0));
+ else
+ ret.push_back(Pair("confirmations", pcoinsTip->GetBestBlock()->nHeight - coins.nHeight + 1));
+ ret.push_back(Pair("amount", (boost::int64_t)coins.vout[n].nValue));
+ Object o;
+ o.push_back(Pair("asm", coins.vout[n].scriptPubKey.ToString()));
+ o.push_back(Pair("hex", HexStr(coins.vout[n].scriptPubKey.begin(), coins.vout[n].scriptPubKey.end())));
+ ret.push_back(Pair("scriptPubKey", o));
+ ret.push_back(Pair("version", coins.nVersion));
+ ret.push_back(Pair("coinbase", coins.fCoinBase));
+
+ return ret;
+}
diff --git a/src/txdb-leveldb.cpp b/src/txdb-leveldb.cpp
index 4e2abe63d7..7c72ccac02 100644
--- a/src/txdb-leveldb.cpp
+++ b/src/txdb-leveldb.cpp
@@ -97,6 +97,41 @@ bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
return Read('l', nFile);
}
+bool CCoinsViewDB::GetStats(CCoinsStats &stats) {
+ leveldb::Iterator *pcursor = db.NewIterator();
+ pcursor->SeekToFirst();
+
+ while (pcursor->Valid()) {
+ try {
+ leveldb::Slice slKey = pcursor->key();
+ CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
+ char chType;
+ ssKey >> chType;
+ if (chType == 'c' && !fRequestShutdown) {
+ leveldb::Slice slValue = pcursor->value();
+ CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
+ CCoins coins;
+ ssValue >> coins;
+ uint256 txhash;
+ ssKey >> txhash;
+
+ stats.nTransactions++;
+ BOOST_FOREACH(const CTxOut &out, coins.vout) {
+ if (!out.IsNull())
+ stats.nTransactionOutputs++;
+ }
+ stats.nSerializedSize += 32 + slValue.size();
+ }
+ pcursor->Next();
+ } catch (std::exception &e) {
+ return error("%s() : deserialize error", __PRETTY_FUNCTION__);
+ }
+ }
+ delete pcursor;
+ stats.nHeight = GetBestBlock()->nHeight;
+ return true;
+}
+
bool CBlockTreeDB::LoadBlockIndexGuts()
{
leveldb::Iterator *pcursor = NewIterator();
diff --git a/src/txdb-leveldb.h b/src/txdb-leveldb.h
index 1254422cf0..123ec00d23 100644
--- a/src/txdb-leveldb.h
+++ b/src/txdb-leveldb.h
@@ -22,6 +22,7 @@ public:
CBlockIndex *GetBestBlock();
bool SetBestBlock(CBlockIndex *pindex);
bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
+ bool GetStats(CCoinsStats &stats);
};
/** Access to the block database (blktree/) */