Add gettxout and gettxoutsetinfo RPCs

This commit is contained in:
Pieter Wuille 2012-09-25 23:04:54 +02:00
parent e1bfbab802
commit beeb57610c
7 changed files with 120 additions and 2 deletions

View file

@ -256,6 +256,8 @@ static const CRPCCommand vRPCCommands[] =
{ "decoderawtransaction", &decoderawtransaction, false, false }, { "decoderawtransaction", &decoderawtransaction, false, false },
{ "signrawtransaction", &signrawtransaction, false, false }, { "signrawtransaction", &signrawtransaction, false, false },
{ "sendrawtransaction", &sendrawtransaction, false, false }, { "sendrawtransaction", &sendrawtransaction, false, false },
{ "gettxoutsetinfo", &gettxoutsetinfo, true, false },
{ "gettxout", &gettxout, true, false },
}; };
CRPCTable::CRPCTable() 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 == "createrawtransaction" && n > 1) ConvertTo<Object>(params[1]);
if (strMethod == "signrawtransaction" && n > 1) ConvertTo<Array>(params[1], true); if (strMethod == "signrawtransaction" && n > 1) ConvertTo<Array>(params[1], true);
if (strMethod == "signrawtransaction" && n > 2) ConvertTo<Array>(params[2], 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; return params;
} }

View file

@ -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 getrawmempool(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getblockhash(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 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 #endif

View file

@ -171,6 +171,7 @@ bool CCoinsView::HaveCoins(uint256 txid) { return false; }
CBlockIndex *CCoinsView::GetBestBlock() { return NULL; } CBlockIndex *CCoinsView::GetBestBlock() { return NULL; }
bool CCoinsView::SetBestBlock(CBlockIndex *pindex) { return false; } bool CCoinsView::SetBestBlock(CBlockIndex *pindex) { return false; }
bool CCoinsView::BatchWrite(const std::map<uint256, CCoins> &mapCoins, 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) { } 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); } bool CCoinsViewBacked::SetBestBlock(CBlockIndex *pindex) { return base->SetBestBlock(pindex); }
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; } 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::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) { } CCoinsViewCache::CCoinsViewCache(CCoinsView &baseIn, bool fDummy) : CCoinsViewBacked(baseIn), pindexTip(NULL) { }

View file

@ -1791,6 +1791,16 @@ public:
extern CTxMemPool mempool; 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. */ /** Abstract view on the open txout dataset. */
class CCoinsView class CCoinsView
{ {
@ -1811,6 +1821,7 @@ public:
// Modify the currently active block index // Modify the currently active block index
virtual bool SetBestBlock(CBlockIndex *pindex); virtual bool SetBestBlock(CBlockIndex *pindex);
virtual bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex); virtual bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
virtual bool GetStats(CCoinsStats &stats);
}; };
/** CCoinsView backed by another CCoinsView */ /** CCoinsView backed by another CCoinsView */
@ -1828,6 +1839,7 @@ public:
bool SetBestBlock(CBlockIndex *pindex); bool SetBestBlock(CBlockIndex *pindex);
void SetBackend(CCoinsView &viewIn); void SetBackend(CCoinsView &viewIn);
bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex); 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 */ /** CCoinsView that adds a memory cache for transactions to another CCoinsView */

View file

@ -159,7 +159,69 @@ Value getblock(const Array& params, bool fHelp)
return blockToJSON(block, pblockindex); 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;
}

View file

@ -97,6 +97,41 @@ bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
return Read('l', 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() bool CBlockTreeDB::LoadBlockIndexGuts()
{ {
leveldb::Iterator *pcursor = NewIterator(); leveldb::Iterator *pcursor = NewIterator();

View file

@ -22,6 +22,7 @@ public:
CBlockIndex *GetBestBlock(); CBlockIndex *GetBestBlock();
bool SetBestBlock(CBlockIndex *pindex); bool SetBestBlock(CBlockIndex *pindex);
bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex); bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
bool GetStats(CCoinsStats &stats);
}; };
/** Access to the block database (blktree/) */ /** Access to the block database (blktree/) */