Switch CCoinsView and chainstate db from per-txid to per-txout
This patch makes several related changes: * Changes the CCoinsView virtual methods (GetCoins, HaveCoins, ...) to be COutPoint/Coin-based rather than txid/CCoins-based. * Changes the chainstate db to a new incompatible format that is also COutPoint/Coin based. * Implements reconstruction code for hash_serialized_2. * Adapts the coins_tests unit tests (thanks to Russell Yanofsky). A side effect of the new CCoinsView model is that we can no longer use the (unreliable) test for transaction outputs in the UTXO set to determine whether we already have a particular transaction.
This commit is contained in:
+26
-21
@@ -816,24 +816,27 @@ static bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats)
|
||||
stats.nHeight = mapBlockIndex.find(stats.hashBlock)->second->nHeight;
|
||||
}
|
||||
ss << stats.hashBlock;
|
||||
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)) {
|
||||
std::map<uint32_t, Coin> outputs;
|
||||
for (unsigned int i=0; i<coins.vout.size(); i++) {
|
||||
CTxOut &out = coins.vout[i];
|
||||
if (!out.IsNull()) {
|
||||
outputs[i] = Coin(std::move(out), coins.nHeight, coins.fCoinBase);
|
||||
}
|
||||
COutPoint key;
|
||||
Coin coin;
|
||||
if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {
|
||||
if (!outputs.empty() && key.hash != prevkey) {
|
||||
ApplyStats(stats, ss, prevkey, outputs);
|
||||
outputs.clear();
|
||||
}
|
||||
ApplyStats(stats, ss, key, outputs);
|
||||
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.nDiskSize = view->EstimateSize();
|
||||
return true;
|
||||
@@ -973,35 +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) || mempool.isSpent(COutPoint(hash, n))) // TODO: this should be done by the CCoinsViewMemPool
|
||||
if (!view.GetCoins(out, coin) || mempool.isSpent(out)) { // TODO: filtering spent coins should be done by the CCoinsViewMemPool
|
||||
return NullUniValue;
|
||||
}
|
||||
} else {
|
||||
if (!pcoinsTip->GetCoins(hash, coins))
|
||||
if (!pcoinsTip->GetCoins(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("coinbase", coins.fCoinBase));
|
||||
ret.push_back(Pair("coinbase", (bool)coin.fCoinBase));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user