Merge pull request #1949 from sipa/bugfix_maturity

Ultraprune bugfixes
This commit is contained in:
Jeff Garzik 2012-10-22 17:39:16 -07:00
commit 16eec89042
2 changed files with 47 additions and 8 deletions

View File

@ -691,13 +691,21 @@ bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs,
if (fCheckInputs) if (fCheckInputs)
{ {
CCoinsViewCache &view = *pcoinsTip; CCoinsView dummy;
CCoinsViewCache view(dummy);
{
LOCK(cs);
CCoinsViewMemPool viewMemPool(*pcoinsTip, *this);
view.SetBackend(viewMemPool);
// do we already have it? // do we already have it?
if (view.HaveCoins(hash)) if (view.HaveCoins(hash))
return false; return false;
// do all inputs exist? // do all inputs exist?
// Note that this does not check for the presence of actual outputs (see the next check for that),
// only helps filling in pfMissingInputs (to determine missing vs spent).
BOOST_FOREACH(const CTxIn txin, tx.vin) { BOOST_FOREACH(const CTxIn txin, tx.vin) {
if (!view.HaveCoins(txin.prevout.hash)) { if (!view.HaveCoins(txin.prevout.hash)) {
if (pfMissingInputs) if (pfMissingInputs)
@ -706,8 +714,16 @@ bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs,
} }
} }
// are the actual inputs available?
if (!tx.HaveInputs(view)) if (!tx.HaveInputs(view))
return error("CTxMemPool::accept() : inputs already spent"); return error("CTxMemPool::accept() : inputs already spent");
// Bring the best block into scope
view.GetBestBlock();
// we have all inputs cached now, so switch back to dummy, so we don't need to keep lock on mempool
view.SetBackend(dummy);
}
// Check for non-standard pay-to-script-hash in inputs // Check for non-standard pay-to-script-hash in inputs
if (!tx.AreInputsStandard(view) && !fTestNet) if (!tx.AreInputsStandard(view) && !fTestNet)
@ -738,7 +754,6 @@ bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs,
int64 nNow = GetTime(); int64 nNow = GetTime();
{ {
LOCK(cs);
// Use an exponentially decaying ~10-minute window: // Use an exponentially decaying ~10-minute window:
dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime)); dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime));
nLastTime = nNow; nLastTime = nNow;
@ -1319,7 +1334,9 @@ bool CTransaction::CheckInputs(CCoinsViewCache &inputs, enum CheckSig_mode csmod
if (!HaveInputs(inputs)) if (!HaveInputs(inputs))
return error("CheckInputs() : %s inputs unavailable", GetHash().ToString().substr(0,10).c_str()); return error("CheckInputs() : %s inputs unavailable", GetHash().ToString().substr(0,10).c_str());
CBlockIndex *pindexBlock = inputs.GetBestBlock(); // While checking, GetBestBlock() refers to the parent block.
// This is also true for mempool checks.
int nSpendHeight = inputs.GetBestBlock()->nHeight + 1;
int64 nValueIn = 0; int64 nValueIn = 0;
int64 nFees = 0; int64 nFees = 0;
for (unsigned int i = 0; i < vin.size(); i++) for (unsigned int i = 0; i < vin.size(); i++)
@ -1329,8 +1346,8 @@ bool CTransaction::CheckInputs(CCoinsViewCache &inputs, enum CheckSig_mode csmod
// If prev is coinbase, check that it's matured // If prev is coinbase, check that it's matured
if (coins.IsCoinBase()) { if (coins.IsCoinBase()) {
if (pindexBlock->nHeight - coins.nHeight < COINBASE_MATURITY) if (nSpendHeight - coins.nHeight < COINBASE_MATURITY)
return error("CheckInputs() : tried to spend coinbase at depth %d", pindexBlock->nHeight - coins.nHeight); return error("CheckInputs() : tried to spend coinbase at depth %d", nSpendHeight - coins.nHeight);
} }
// Check for negative or overflow input values // Check for negative or overflow input values
@ -1595,6 +1612,9 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
blockundo.vtxundo.push_back(txundo); blockundo.vtxundo.push_back(txundo);
} }
if (vtx[0].GetValueOut() > GetBlockValue(pindex->nHeight, nFees))
return false;
if (fJustCheck) if (fJustCheck)
return true; return true;
@ -1951,9 +1971,13 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot) const
if (!tx.CheckTransaction()) if (!tx.CheckTransaction())
return DoS(tx.nDoS, error("CheckBlock() : CheckTransaction failed")); return DoS(tx.nDoS, error("CheckBlock() : CheckTransaction failed"));
// Build the merkle tree already. We need it anyway later, and it makes the
// block cache the transaction hashes, which means they don't need to be
// recalculated many times during this block's validation.
BuildMerkleTree();
// Check for duplicate txids. This is caught by ConnectInputs(), // Check for duplicate txids. This is caught by ConnectInputs(),
// but catching it earlier avoids a potential DoS attack: // but catching it earlier avoids a potential DoS attack:
BuildMerkleTree();
set<uint256> uniqueTx; set<uint256> uniqueTx;
for (unsigned int i=0; i<vtx.size(); i++) { for (unsigned int i=0; i<vtx.size(); i++) {
uniqueTx.insert(GetTxHash(i)); uniqueTx.insert(GetTxHash(i));
@ -3825,7 +3849,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey)
int64 nValueIn = coins.vout[txin.prevout.n].nValue; int64 nValueIn = coins.vout[txin.prevout.n].nValue;
nTotalIn += nValueIn; nTotalIn += nValueIn;
int nConf = pindexPrev->nHeight - coins.nHeight; int nConf = pindexPrev->nHeight - coins.nHeight + 1;
dPriority += (double)nValueIn * nConf; dPriority += (double)nValueIn * nConf;
} }

View File

@ -1820,7 +1820,11 @@ public:
// Modify the currently active block index // Modify the currently active block index
virtual bool SetBestBlock(CBlockIndex *pindex); virtual bool SetBestBlock(CBlockIndex *pindex);
// Do a bulk modification (multiple SetCoins + one SetBestBlock)
virtual bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex); virtual bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
// Calculate statistics about the unspent transaction output set
virtual bool GetStats(CCoinsStats &stats); virtual bool GetStats(CCoinsStats &stats);
}; };
@ -1851,14 +1855,25 @@ protected:
public: public:
CCoinsViewCache(CCoinsView &baseIn, bool fDummy = false); CCoinsViewCache(CCoinsView &baseIn, bool fDummy = false);
// Standard CCoinsView methods
bool GetCoins(uint256 txid, CCoins &coins); bool GetCoins(uint256 txid, CCoins &coins);
bool SetCoins(uint256 txid, const CCoins &coins); bool SetCoins(uint256 txid, const CCoins &coins);
bool HaveCoins(uint256 txid); bool HaveCoins(uint256 txid);
CCoins &GetCoins(uint256 txid);
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);
// Return a modifiable reference to a CCoins. Check HaveCoins first.
// Many methods explicitly require a CCoinsViewCache because of this method, to reduce
// copying.
CCoins &GetCoins(uint256 txid);
// Push the modifications applied to this cache to its base.
// Failure to call this method before destruction will cause the changes to be forgotten.
bool Flush(); bool Flush();
// Calculate the size of the cache (in number of transactions)
unsigned int GetCacheSize(); unsigned int GetCacheSize();
private: private: