Added mapSerials consensus rules to prohibit double-spending.

This commit is contained in:
Sean Bowe
2016-01-08 08:37:17 -07:00
parent 03bff15fe2
commit d66877afb3
8 changed files with 224 additions and 4 deletions

View File

@@ -99,6 +99,11 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
const CTransaction& tx = mapTx[hash].GetTx();
for (unsigned int i = 0; i < tx.vin.size(); i++)
mapNextTx[tx.vin[i].prevout] = CInPoint(&tx, i);
BOOST_FOREACH(const CPourTx &pour, tx.vpour) {
BOOST_FOREACH(const uint256 &serial, pour.serials) {
mapSerials[serial] = &tx;
}
}
nTransactionsUpdated++;
totalTxSize += entry.GetTxSize();
minerPolicyEstimator->processTransaction(entry, fCurrentEstimate);
@@ -143,6 +148,11 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list<CTransaction>& rem
}
BOOST_FOREACH(const CTxIn& txin, tx.vin)
mapNextTx.erase(txin.prevout);
BOOST_FOREACH(const CPourTx& pour, tx.vpour) {
BOOST_FOREACH(const uint256& serial, pour.serials) {
mapSerials.erase(serial);
}
}
removed.push_back(tx);
totalTxSize -= mapTx[hash].GetTxSize();
@@ -219,6 +229,19 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::list<CTransaction>
}
}
}
BOOST_FOREACH(const CPourTx &pour, tx.vpour) {
BOOST_FOREACH(const uint256 &serial, pour.serials) {
std::map<uint256, const CTransaction*>::iterator it = mapSerials.find(serial);
if (it != mapSerials.end()) {
const CTransaction &txConflict = *it->second;
if (txConflict != tx)
{
remove(txConflict, removed, true);
}
}
}
}
}
/**
@@ -291,6 +314,15 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
assert(it3->second.n == i);
i++;
}
BOOST_FOREACH(const CPourTx &pour, tx.vpour) {
BOOST_FOREACH(const uint256 &serial, pour.serials) {
assert(!pcoins->GetSerial(serial));
}
// TODO: chained pours
libzerocash::IncrementalMerkleTree tree(INCREMENTAL_MERKLE_TREE_DEPTH);
assert(pcoins->GetAnchorAt(pour.anchor, tree));
}
if (fDependsWait)
waitingOnDependants.push_back(&it->second);
else {
@@ -324,6 +356,14 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
assert(it->first == it->second.ptx->vin[it->second.n].prevout);
}
for (std::map<uint256, const CTransaction*>::const_iterator it = mapSerials.begin(); it != mapSerials.end(); it++) {
uint256 hash = it->second->GetHash();
map<uint256, CTxMemPoolEntry>::const_iterator it2 = mapTx.find(hash);
const CTransaction& tx = it2->second.GetTx();
assert(it2 != mapTx.end());
assert(&tx == it->second);
}
assert(totalTxSize == checkTotal);
}
@@ -430,6 +470,13 @@ bool CTxMemPool::HasNoInputsOf(const CTransaction &tx) const
CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView *baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { }
bool CCoinsViewMemPool::GetSerial(const uint256 &serial) const {
if (mempool.mapSerials.count(serial))
return true;
return base->GetSerial(serial);
}
bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) const {
// If an entry in the mempool exists, always return that one, as it's guaranteed to never
// conflict with the underlying cache, and it cannot have pruned entries (as it contains full)