mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-01-19 14:53:43 +01:00
txdb: Add Cursor() method to CCoinsView to iterate over UTXO set
Add a method Cursor() to CCoinsView that returns a cursor which can be used to iterate over the whole UTXO set. - rpc: Change gettxoutsetinfo to use new Cursor method - txdb: Remove GetStats method - Now that GetStats is implemented in terms of Cursor, remove it.
This commit is contained in:
78
src/txdb.cpp
78
src/txdb.cpp
@@ -94,50 +94,52 @@ bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
|
||||
return Read(DB_LAST_BLOCK, nFile);
|
||||
}
|
||||
|
||||
bool CCoinsViewDB::GetStats(CCoinsStats &stats) const {
|
||||
CCoinsViewCursor *CCoinsViewDB::Cursor() const
|
||||
{
|
||||
CCoinsViewDBCursor *i = new CCoinsViewDBCursor(const_cast<CDBWrapper*>(&db)->NewIterator(), GetBestBlock());
|
||||
/* It seems that there are no "const iterators" for LevelDB. Since we
|
||||
only need read operations on it, use a const-cast to get around
|
||||
that restriction. */
|
||||
boost::scoped_ptr<CDBIterator> pcursor(const_cast<CDBWrapper*>(&db)->NewIterator());
|
||||
pcursor->Seek(DB_COINS);
|
||||
i->pcursor->Seek(DB_COINS);
|
||||
// Cache key of first record
|
||||
i->pcursor->GetKey(i->keyTmp);
|
||||
return i;
|
||||
}
|
||||
|
||||
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
|
||||
stats.hashBlock = GetBestBlock();
|
||||
ss << stats.hashBlock;
|
||||
CAmount nTotalAmount = 0;
|
||||
while (pcursor->Valid()) {
|
||||
boost::this_thread::interruption_point();
|
||||
std::pair<char, uint256> key;
|
||||
CCoins coins;
|
||||
if (pcursor->GetKey(key) && key.first == DB_COINS) {
|
||||
if (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("CCoinsViewDB::GetStats() : unable to read value");
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
pcursor->Next();
|
||||
bool CCoinsViewDBCursor::GetKey(uint256 &key) const
|
||||
{
|
||||
// Return cached key
|
||||
if (keyTmp.first == DB_COINS) {
|
||||
key = keyTmp.second;
|
||||
return true;
|
||||
}
|
||||
{
|
||||
LOCK(cs_main);
|
||||
stats.nHeight = mapBlockIndex.find(stats.hashBlock)->second->nHeight;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCoinsViewDBCursor::GetValue(CCoins &coins) const
|
||||
{
|
||||
return pcursor->GetValue(coins);
|
||||
}
|
||||
|
||||
unsigned int CCoinsViewDBCursor::GetValueSize() const
|
||||
{
|
||||
return pcursor->GetValueSize();
|
||||
}
|
||||
|
||||
bool CCoinsViewDBCursor::Valid() const
|
||||
{
|
||||
return keyTmp.first == DB_COINS;
|
||||
}
|
||||
|
||||
void CCoinsViewDBCursor::Next()
|
||||
{
|
||||
pcursor->Next();
|
||||
if (pcursor->Valid()) {
|
||||
bool ok = pcursor->GetKey(keyTmp);
|
||||
assert(ok); // If GetKey fails here something must be wrong with underlying database, we cannot handle that here
|
||||
} else {
|
||||
keyTmp.first = 0; // Invalidate cached key after last record so that Valid() and GetKey() return false
|
||||
}
|
||||
stats.hashSerialized = ss.GetHash();
|
||||
stats.nTotalAmount = nTotalAmount;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::WriteBatchSync(const std::vector<std::pair<int, const CBlockFileInfo*> >& fileInfo, int nLastFile, const std::vector<const CBlockIndex*>& blockinfo) {
|
||||
|
||||
Reference in New Issue
Block a user