mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-01-20 07:09:15 +01:00
Merge pull request #3199 from sipa/mempoolmove
Cleanup refactoring of coins/mempool
This commit is contained in:
195
src/main.cpp
195
src/main.cpp
@@ -229,128 +229,6 @@ CBlockIndex *CChain::FindFork(const CBlockLocator &locator) const {
|
||||
return Genesis();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// CCoinsView implementations
|
||||
//
|
||||
|
||||
bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) { return false; }
|
||||
bool CCoinsView::SetCoins(const uint256 &txid, const CCoins &coins) { return false; }
|
||||
bool CCoinsView::HaveCoins(const uint256 &txid) { return false; }
|
||||
CBlockIndex *CCoinsView::GetBestBlock() { return NULL; }
|
||||
bool CCoinsView::SetBestBlock(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) { }
|
||||
bool CCoinsViewBacked::GetCoins(const uint256 &txid, CCoins &coins) { return base->GetCoins(txid, coins); }
|
||||
bool CCoinsViewBacked::SetCoins(const uint256 &txid, const CCoins &coins) { return base->SetCoins(txid, coins); }
|
||||
bool CCoinsViewBacked::HaveCoins(const uint256 &txid) { return base->HaveCoins(txid); }
|
||||
CBlockIndex *CCoinsViewBacked::GetBestBlock() { return base->GetBestBlock(); }
|
||||
bool CCoinsViewBacked::SetBestBlock(CBlockIndex *pindex) { return base->SetBestBlock(pindex); }
|
||||
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::GetStats(CCoinsStats &stats) { return base->GetStats(stats); }
|
||||
|
||||
CCoinsViewCache::CCoinsViewCache(CCoinsView &baseIn, bool fDummy) : CCoinsViewBacked(baseIn), pindexTip(NULL) { }
|
||||
|
||||
bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) {
|
||||
if (cacheCoins.count(txid)) {
|
||||
coins = cacheCoins[txid];
|
||||
return true;
|
||||
}
|
||||
if (base->GetCoins(txid, coins)) {
|
||||
cacheCoins[txid] = coins;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::map<uint256,CCoins>::iterator CCoinsViewCache::FetchCoins(const uint256 &txid) {
|
||||
std::map<uint256,CCoins>::iterator it = cacheCoins.lower_bound(txid);
|
||||
if (it != cacheCoins.end() && it->first == txid)
|
||||
return it;
|
||||
CCoins tmp;
|
||||
if (!base->GetCoins(txid,tmp))
|
||||
return cacheCoins.end();
|
||||
std::map<uint256,CCoins>::iterator ret = cacheCoins.insert(it, std::make_pair(txid, CCoins()));
|
||||
tmp.swap(ret->second);
|
||||
return ret;
|
||||
}
|
||||
|
||||
CCoins &CCoinsViewCache::GetCoins(const uint256 &txid) {
|
||||
std::map<uint256,CCoins>::iterator it = FetchCoins(txid);
|
||||
assert(it != cacheCoins.end());
|
||||
return it->second;
|
||||
}
|
||||
|
||||
bool CCoinsViewCache::SetCoins(const uint256 &txid, const CCoins &coins) {
|
||||
cacheCoins[txid] = coins;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCoinsViewCache::HaveCoins(const uint256 &txid) {
|
||||
return FetchCoins(txid) != cacheCoins.end();
|
||||
}
|
||||
|
||||
CBlockIndex *CCoinsViewCache::GetBestBlock() {
|
||||
if (pindexTip == NULL)
|
||||
pindexTip = base->GetBestBlock();
|
||||
return pindexTip;
|
||||
}
|
||||
|
||||
bool CCoinsViewCache::SetBestBlock(CBlockIndex *pindex) {
|
||||
pindexTip = pindex;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCoinsViewCache::BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex) {
|
||||
for (std::map<uint256, CCoins>::const_iterator it = mapCoins.begin(); it != mapCoins.end(); it++)
|
||||
cacheCoins[it->first] = it->second;
|
||||
pindexTip = pindex;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCoinsViewCache::Flush() {
|
||||
bool fOk = base->BatchWrite(cacheCoins, pindexTip);
|
||||
if (fOk)
|
||||
cacheCoins.clear();
|
||||
return fOk;
|
||||
}
|
||||
|
||||
unsigned int CCoinsViewCache::GetCacheSize() {
|
||||
return cacheCoins.size();
|
||||
}
|
||||
|
||||
/** Helper; lookup from tip (used calling mempool.check()
|
||||
NOTE: code calling this MUST hold the cs_main lock so
|
||||
another thread doesn't modify pcoinsTip. When we switch
|
||||
to C++11 this should be replaced by lambda expressions...
|
||||
**/
|
||||
static CCoins &LookupFromTip(const uint256& hash) {
|
||||
return pcoinsTip->GetCoins(hash);
|
||||
}
|
||||
|
||||
/** CCoinsView that brings transactions from a memorypool into view.
|
||||
It does not check for spendings by memory pool transactions. */
|
||||
CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView &baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { }
|
||||
|
||||
bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) {
|
||||
if (base->GetCoins(txid, coins))
|
||||
return true;
|
||||
CTransaction tx;
|
||||
if (mempool.lookup(txid, tx)) {
|
||||
coins = CCoins(tx, MEMPOOL_HEIGHT);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCoinsViewMemPool::HaveCoins(const uint256 &txid) {
|
||||
return mempool.exists(txid) || base->HaveCoins(txid);
|
||||
}
|
||||
|
||||
CCoinsViewCache *pcoinsTip = NULL;
|
||||
CBlockTreeDB *pblocktree = NULL;
|
||||
|
||||
@@ -1430,25 +1308,6 @@ void UpdateTime(CBlockHeader& block, const CBlockIndex* pindexPrev)
|
||||
|
||||
|
||||
|
||||
const CTxOut &CCoinsViewCache::GetOutputFor(const CTxIn& input)
|
||||
{
|
||||
const CCoins &coins = GetCoins(input.prevout.hash);
|
||||
assert(coins.IsAvailable(input.prevout.n));
|
||||
return coins.vout[input.prevout.n];
|
||||
}
|
||||
|
||||
int64_t CCoinsViewCache::GetValueIn(const CTransaction& tx)
|
||||
{
|
||||
if (tx.IsCoinBase())
|
||||
return 0;
|
||||
|
||||
int64_t nResult = 0;
|
||||
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
||||
nResult += GetOutputFor(tx.vin[i]).nValue;
|
||||
|
||||
return nResult;
|
||||
}
|
||||
|
||||
void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight, const uint256 &txhash)
|
||||
{
|
||||
// mark inputs spent
|
||||
@@ -1465,27 +1324,6 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach
|
||||
assert(inputs.SetCoins(txhash, CCoins(tx, nHeight)));
|
||||
}
|
||||
|
||||
bool CCoinsViewCache::HaveInputs(const CTransaction& tx)
|
||||
{
|
||||
if (!tx.IsCoinBase()) {
|
||||
// first check whether information about the prevout hash is available
|
||||
for (unsigned int i = 0; i < tx.vin.size(); i++) {
|
||||
const COutPoint &prevout = tx.vin[i].prevout;
|
||||
if (!HaveCoins(prevout.hash))
|
||||
return false;
|
||||
}
|
||||
|
||||
// then check whether the actual outputs are available
|
||||
for (unsigned int i = 0; i < tx.vin.size(); i++) {
|
||||
const COutPoint &prevout = tx.vin[i].prevout;
|
||||
const CCoins &coins = GetCoins(prevout.hash);
|
||||
if (!coins.IsAvailable(prevout.n))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CScriptCheck::operator()() const {
|
||||
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
|
||||
if (!VerifyScript(scriptSig, scriptPubKey, *ptxTo, nIn, nFlags, nHashType))
|
||||
@@ -1512,7 +1350,8 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCach
|
||||
|
||||
// While checking, GetBestBlock() refers to the parent block.
|
||||
// This is also true for mempool checks.
|
||||
int nSpendHeight = inputs.GetBestBlock()->nHeight + 1;
|
||||
CBlockIndex *pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second;
|
||||
int nSpendHeight = pindexPrev->nHeight + 1;
|
||||
int64_t nValueIn = 0;
|
||||
int64_t nFees = 0;
|
||||
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
||||
@@ -1588,7 +1427,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCach
|
||||
|
||||
bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool* pfClean)
|
||||
{
|
||||
assert(pindex == view.GetBestBlock());
|
||||
assert(pindex->GetBlockHash() == view.GetBestBlock());
|
||||
|
||||
if (pfClean)
|
||||
*pfClean = false;
|
||||
@@ -1664,7 +1503,7 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
|
||||
}
|
||||
|
||||
// move best block pointer to prevout block
|
||||
view.SetBestBlock(pindex->pprev);
|
||||
view.SetBestBlock(pindex->pprev->GetBlockHash());
|
||||
|
||||
if (pfClean) {
|
||||
*pfClean = fClean;
|
||||
@@ -1713,12 +1552,13 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
|
||||
return false;
|
||||
|
||||
// verify that the view's current state corresponds to the previous block
|
||||
assert(pindex->pprev == view.GetBestBlock());
|
||||
uint256 hashPrevBlock = pindex->pprev == NULL ? uint256(0) : pindex->pprev->GetBlockHash();
|
||||
assert(hashPrevBlock == view.GetBestBlock());
|
||||
|
||||
// Special case for the genesis block, skipping connection of its transactions
|
||||
// (its coinbase is unspendable)
|
||||
if (block.GetHash() == Params().HashGenesisBlock()) {
|
||||
view.SetBestBlock(pindex);
|
||||
view.SetBestBlock(pindex->GetBlockHash());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1855,7 +1695,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
|
||||
return state.Abort(_("Failed to write transaction index"));
|
||||
|
||||
// add this block to the view's block chain
|
||||
assert(view.SetBestBlock(pindex));
|
||||
assert(view.SetBestBlock(pindex->GetBlockHash()));
|
||||
|
||||
// Watch for transactions paying to me
|
||||
for (unsigned int i = 0; i < block.vtx.size(); i++)
|
||||
@@ -1866,14 +1706,16 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
|
||||
|
||||
bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
|
||||
{
|
||||
mempool.check(&LookupFromTip);
|
||||
mempool.check(pcoinsTip);
|
||||
|
||||
// All modifications to the coin state will be done in this cache.
|
||||
// Only when all have succeeded, we push it to pcoinsTip.
|
||||
CCoinsViewCache view(*pcoinsTip, true);
|
||||
|
||||
// Find the fork (typically, there is none)
|
||||
CBlockIndex* pfork = view.GetBestBlock();
|
||||
std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(view.GetBestBlock());
|
||||
CBlockIndex* ptip = (it != mapBlockIndex.end()) ? it->second : NULL;
|
||||
CBlockIndex* pfork = ptip;
|
||||
CBlockIndex* plonger = pindexNew;
|
||||
while (pfork && pfork != plonger)
|
||||
{
|
||||
@@ -1889,7 +1731,7 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
|
||||
|
||||
// List of what to disconnect (typically nothing)
|
||||
vector<CBlockIndex*> vDisconnect;
|
||||
for (CBlockIndex* pindex = view.GetBestBlock(); pindex != pfork; pindex = pindex->pprev)
|
||||
for (CBlockIndex* pindex = ptip; pindex != pfork; pindex = pindex->pprev)
|
||||
vDisconnect.push_back(pindex);
|
||||
|
||||
// List of what to connect (typically only pindexNew)
|
||||
@@ -1989,7 +1831,7 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
|
||||
mempool.removeConflicts(tx);
|
||||
}
|
||||
|
||||
mempool.check(&LookupFromTip);
|
||||
mempool.check(pcoinsTip);
|
||||
|
||||
// Update best block in wallet (so we can detect restored wallets)
|
||||
if ((pindexNew->nHeight % 20160) == 0 || (!fIsInitialDownload && (pindexNew->nHeight % 144) == 0))
|
||||
@@ -2730,9 +2572,10 @@ bool static LoadBlockIndexDB()
|
||||
LogPrintf("LoadBlockIndexDB(): transaction index %s\n", fTxIndex ? "enabled" : "disabled");
|
||||
|
||||
// Load pointer to end of best chain
|
||||
chainActive.SetTip(pcoinsTip->GetBestBlock());
|
||||
if (chainActive.Tip() == NULL)
|
||||
std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
|
||||
if (it == mapBlockIndex.end())
|
||||
return true;
|
||||
chainActive.SetTip(it->second);
|
||||
LogPrintf("LoadBlockIndexDB(): hashBestChain=%s height=%d date=%s\n",
|
||||
chainActive.Tip()->GetBlockHash().ToString().c_str(), chainActive.Height(),
|
||||
DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()).c_str());
|
||||
@@ -3580,7 +3423,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
||||
CValidationState state;
|
||||
if (AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs))
|
||||
{
|
||||
mempool.check(&LookupFromTip);
|
||||
mempool.check(pcoinsTip);
|
||||
RelayTransaction(tx, inv.hash);
|
||||
mapAlreadyAskedFor.erase(inv);
|
||||
vWorkQueue.push_back(inv.hash);
|
||||
@@ -3616,7 +3459,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
||||
vEraseQueue.push_back(orphanHash);
|
||||
LogPrint("mempool", " removed orphan tx %s\n", orphanHash.ToString().c_str());
|
||||
}
|
||||
mempool.check(&LookupFromTip);
|
||||
mempool.check(pcoinsTip);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user