mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-11-13 07:28:59 +01:00
Merge #10195: Switch chainstate db and cache to per-txout model
589827975scripted-diff: various renames for per-utxo consistency (Pieter Wuille)a5e02bc7fIncrease travis unit test timeout (Pieter Wuille)73de2c1ffRename CCoinsCacheEntry::coins to coin (Pieter Wuille)119e552f7Merge CCoinsViewCache's GetOutputFor and AccessCoin (Pieter Wuille)580b02309[MOVEONLY] Move old CCoins class to txdb.cpp (Pieter Wuille)8b25d2c0cUpgrade from per-tx database to per-txout (Pieter Wuille)b2af357f3Reduce reserved memory space for flushing (Pieter Wuille)41aa5b79aPack Coin more tightly (Pieter Wuille)97072d668Remove unused CCoins methods (Pieter Wuille)ce23efaa5Extend coins_tests (Pieter Wuille)508307968Switch CCoinsView and chainstate db from per-txid to per-txout (Pieter Wuille)4ec0d9e79Refactor GetUTXOStats in preparation for per-COutPoint iteration (Pieter Wuille)13870b56fReplace CCoins-based CTxMemPool::pruneSpent with isSpent (Pieter Wuille)05293f3cbRemove ModifyCoins/ModifyNewCoins (Pieter Wuille)961e48397Switch tests from ModifyCoins to AddCoin/SpendCoin (Pieter Wuille)8b3868c1bSwitch CScriptCheck to use Coin instead of CCoins (Pieter Wuille)c87b957a3Only pass things committed to by tx's witness hash to CScriptCheck (Matt Corallo)f68cdfe92Switch from per-tx to per-txout CCoinsViewCache methods in some places (Pieter Wuille)000391132Introduce new per-txout CCoinsViewCache functions (Pieter Wuille)bd83111a0Optimization: Coin&& to ApplyTxInUndo (Pieter Wuille)cb2c7fdacReplace CTxInUndo with Coin (Pieter Wuille)422634e2fIntroduce Coin, a single unspent output (Pieter Wuille)7d991b55dStore/allow tx metadata in all undo records (Pieter Wuille)c3aa0c119Report on-disk size in gettxoutsetinfo (Pieter Wuille)d34242430Remove/ignore tx version in utxo and undo (Pieter Wuille)7e0032290Add specialization of SipHash for 256 + 32 bit data (Pieter Wuille)e484652fcIntroduce CHashVerifier to hash read data (Pieter Wuille)f54580e7eerror() in disconnect for disk corruption, not inconsistency (Pieter Wuille)e66dbde6dAdd SizeEstimate to CDBBatch (Pieter Wuille) Tree-SHA512: ce1fb1e40c77d38915cd02189fab7a8b125c7f44d425c85579d872c3bede3a437760997907c99d7b3017ced1c2de54b2ac7223d99d83a6658fe5ef61edef1de3
This commit is contained in:
@@ -781,13 +781,29 @@ struct CCoinsStats
|
||||
uint256 hashBlock;
|
||||
uint64_t nTransactions;
|
||||
uint64_t nTransactionOutputs;
|
||||
uint64_t nSerializedSize;
|
||||
uint256 hashSerialized;
|
||||
uint64_t nDiskSize;
|
||||
CAmount nTotalAmount;
|
||||
|
||||
CCoinsStats() : nHeight(0), nTransactions(0), nTransactionOutputs(0), nSerializedSize(0), nTotalAmount(0) {}
|
||||
CCoinsStats() : nHeight(0), nTransactions(0), nTransactionOutputs(0), nTotalAmount(0) {}
|
||||
};
|
||||
|
||||
static void ApplyStats(CCoinsStats &stats, CHashWriter& ss, const uint256& hash, const std::map<uint32_t, Coin>& outputs)
|
||||
{
|
||||
assert(!outputs.empty());
|
||||
ss << hash;
|
||||
ss << VARINT(outputs.begin()->second.nHeight * 2 + outputs.begin()->second.fCoinBase);
|
||||
stats.nTransactions++;
|
||||
for (const auto output : outputs) {
|
||||
ss << VARINT(output.first + 1);
|
||||
ss << *(const CScriptBase*)(&output.second.out.scriptPubKey);
|
||||
ss << VARINT(output.second.out.nValue);
|
||||
stats.nTransactionOutputs++;
|
||||
stats.nTotalAmount += output.second.out.nValue;
|
||||
}
|
||||
ss << VARINT(0);
|
||||
}
|
||||
|
||||
//! Calculate statistics about the unspent transaction output set
|
||||
static bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats)
|
||||
{
|
||||
@@ -800,32 +816,29 @@ static bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats)
|
||||
stats.nHeight = mapBlockIndex.find(stats.hashBlock)->second->nHeight;
|
||||
}
|
||||
ss << stats.hashBlock;
|
||||
CAmount nTotalAmount = 0;
|
||||
uint256 prevkey;
|
||||
std::map<uint32_t, Coin> outputs;
|
||||
while (pcursor->Valid()) {
|
||||
boost::this_thread::interruption_point();
|
||||
uint256 key;
|
||||
CCoins coins;
|
||||
if (pcursor->GetKey(key) && pcursor->GetValue(coins)) {
|
||||
stats.nTransactions++;
|
||||
ss << key;
|
||||
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;
|
||||
}
|
||||
COutPoint key;
|
||||
Coin coin;
|
||||
if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {
|
||||
if (!outputs.empty() && key.hash != prevkey) {
|
||||
ApplyStats(stats, ss, prevkey, outputs);
|
||||
outputs.clear();
|
||||
}
|
||||
stats.nSerializedSize += 32 + pcursor->GetValueSize();
|
||||
ss << VARINT(0);
|
||||
prevkey = key.hash;
|
||||
outputs[key.n] = std::move(coin);
|
||||
} else {
|
||||
return error("%s: unable to read value", __func__);
|
||||
}
|
||||
pcursor->Next();
|
||||
}
|
||||
if (!outputs.empty()) {
|
||||
ApplyStats(stats, ss, prevkey, outputs);
|
||||
}
|
||||
stats.hashSerialized = ss.GetHash();
|
||||
stats.nTotalAmount = nTotalAmount;
|
||||
stats.nDiskSize = view->EstimateSize();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -891,8 +904,8 @@ UniValue gettxoutsetinfo(const JSONRPCRequest& request)
|
||||
" \"bestblock\": \"hex\", (string) the best block hash hex\n"
|
||||
" \"transactions\": n, (numeric) The number of transactions\n"
|
||||
" \"txouts\": n, (numeric) The number of output transactions\n"
|
||||
" \"bytes_serialized\": n, (numeric) The serialized size\n"
|
||||
" \"hash_serialized\": \"hash\", (string) The serialized hash\n"
|
||||
" \"disk_size\": n, (numeric) The estimated size of the chainstate on disk\n"
|
||||
" \"total_amount\": x.xxx (numeric) The total amount\n"
|
||||
"}\n"
|
||||
"\nExamples:\n"
|
||||
@@ -909,8 +922,8 @@ UniValue gettxoutsetinfo(const JSONRPCRequest& request)
|
||||
ret.push_back(Pair("bestblock", stats.hashBlock.GetHex()));
|
||||
ret.push_back(Pair("transactions", (int64_t)stats.nTransactions));
|
||||
ret.push_back(Pair("txouts", (int64_t)stats.nTransactionOutputs));
|
||||
ret.push_back(Pair("bytes_serialized", (int64_t)stats.nSerializedSize));
|
||||
ret.push_back(Pair("hash_serialized", stats.hashSerialized.GetHex()));
|
||||
ret.push_back(Pair("hash_serialized_2", stats.hashSerialized.GetHex()));
|
||||
ret.push_back(Pair("disk_size", stats.nDiskSize));
|
||||
ret.push_back(Pair("total_amount", ValueFromAmount(stats.nTotalAmount)));
|
||||
} else {
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
|
||||
@@ -963,37 +976,37 @@ UniValue gettxout(const JSONRPCRequest& request)
|
||||
std::string strHash = request.params[0].get_str();
|
||||
uint256 hash(uint256S(strHash));
|
||||
int n = request.params[1].get_int();
|
||||
COutPoint out(hash, n);
|
||||
bool fMempool = true;
|
||||
if (request.params.size() > 2)
|
||||
fMempool = request.params[2].get_bool();
|
||||
|
||||
CCoins coins;
|
||||
Coin coin;
|
||||
if (fMempool) {
|
||||
LOCK(mempool.cs);
|
||||
CCoinsViewMemPool view(pcoinsTip, mempool);
|
||||
if (!view.GetCoins(hash, coins))
|
||||
if (!view.GetCoin(out, coin) || mempool.isSpent(out)) { // TODO: filtering spent coins should be done by the CCoinsViewMemPool
|
||||
return NullUniValue;
|
||||
mempool.pruneSpent(hash, coins); // TODO: this should be done by the CCoinsViewMemPool
|
||||
}
|
||||
} else {
|
||||
if (!pcoinsTip->GetCoins(hash, coins))
|
||||
if (!pcoinsTip->GetCoin(out, coin)) {
|
||||
return NullUniValue;
|
||||
}
|
||||
}
|
||||
if (n<0 || (unsigned int)n>=coins.vout.size() || coins.vout[n].IsNull())
|
||||
return NullUniValue;
|
||||
|
||||
BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
|
||||
CBlockIndex *pindex = it->second;
|
||||
ret.push_back(Pair("bestblock", pindex->GetBlockHash().GetHex()));
|
||||
if ((unsigned int)coins.nHeight == MEMPOOL_HEIGHT)
|
||||
if (coin.nHeight == MEMPOOL_HEIGHT) {
|
||||
ret.push_back(Pair("confirmations", 0));
|
||||
else
|
||||
ret.push_back(Pair("confirmations", pindex->nHeight - coins.nHeight + 1));
|
||||
ret.push_back(Pair("value", ValueFromAmount(coins.vout[n].nValue)));
|
||||
} else {
|
||||
ret.push_back(Pair("confirmations", (int64_t)(pindex->nHeight - coin.nHeight + 1)));
|
||||
}
|
||||
ret.push_back(Pair("value", ValueFromAmount(coin.out.nValue)));
|
||||
UniValue o(UniValue::VOBJ);
|
||||
ScriptPubKeyToUniv(coins.vout[n].scriptPubKey, o, true);
|
||||
ScriptPubKeyToUniv(coin.out.scriptPubKey, o, true);
|
||||
ret.push_back(Pair("scriptPubKey", o));
|
||||
ret.push_back(Pair("version", coins.nVersion));
|
||||
ret.push_back(Pair("coinbase", coins.fCoinBase));
|
||||
ret.push_back(Pair("coinbase", (bool)coin.fCoinBase));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user