Add gettxout and gettxoutsetinfo RPCs
This commit is contained in:
parent
e1bfbab802
commit
beeb57610c
7 changed files with 120 additions and 2 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) { }
|
||||||
|
|
||||||
|
|
12
src/main.h
12
src/main.h
|
@ -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 */
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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/) */
|
||||||
|
|
Loading…
Reference in a new issue