Added mapSerials consensus rules to prohibit double-spending.
This commit is contained in:
@@ -391,6 +391,15 @@ bool CCoinsViewCache::HavePourRequirements(const CTransaction& tx) const
|
||||
{
|
||||
BOOST_FOREACH(const CPourTx &pour, tx.vpour)
|
||||
{
|
||||
BOOST_FOREACH(const uint256& serial, pour.serials)
|
||||
{
|
||||
if (GetSerial(serial)) {
|
||||
// If the serial is set, this transaction
|
||||
// double-spends!
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
libzerocash::IncrementalMerkleTree tree(INCREMENTAL_MERKLE_TREE_DEPTH);
|
||||
if (!GetAnchorAt(pour.anchor, tree)) {
|
||||
// If we do not have the anchor for the pour,
|
||||
|
||||
@@ -47,6 +47,8 @@
|
||||
#include <boost/thread.hpp>
|
||||
#include <openssl/crypto.h>
|
||||
|
||||
#include "libsnark/common/profiling.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
libzerocash::ZerocashParams *pzerocashParams = NULL;
|
||||
@@ -1266,6 +1268,11 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
// ********************************************************* Step 7i: Load zcash params
|
||||
ZC_LoadParams();
|
||||
|
||||
// These must be disabled for now, they are buggy and we probably don't
|
||||
// want any of libsnark's profiling in production anyway.
|
||||
libsnark::inhibit_profiling_info = true;
|
||||
libsnark::inhibit_profiling_counters = true;
|
||||
|
||||
// ********************************************************* Step 8: load wallet
|
||||
#ifdef ENABLE_WALLET
|
||||
if (fDisableWallet) {
|
||||
|
||||
22
src/main.cpp
22
src/main.cpp
@@ -1036,6 +1036,14 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
||||
return false;
|
||||
}
|
||||
}
|
||||
BOOST_FOREACH(const CPourTx &pour, tx.vpour) {
|
||||
BOOST_FOREACH(const uint256 &serial, pour.serials) {
|
||||
if (pool.mapSerials.count(serial))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
@@ -1491,6 +1499,13 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach
|
||||
}
|
||||
}
|
||||
|
||||
// spend serials
|
||||
BOOST_FOREACH(const CPourTx &pour, tx.vpour) {
|
||||
BOOST_FOREACH(const uint256 &serial, pour.serials) {
|
||||
inputs.SetSerial(serial, true);
|
||||
}
|
||||
}
|
||||
|
||||
// add outputs
|
||||
inputs.ModifyCoins(tx.GetHash())->FromTx(tx, nHeight);
|
||||
}
|
||||
@@ -1772,6 +1787,13 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
|
||||
outs->Clear();
|
||||
}
|
||||
|
||||
// unspend serials
|
||||
BOOST_FOREACH(const CPourTx &pour, tx.vpour) {
|
||||
BOOST_FOREACH(const uint256 &serial, pour.serials) {
|
||||
view.SetSerial(serial, false);
|
||||
}
|
||||
}
|
||||
|
||||
// restore inputs
|
||||
if (i > 0) { // not coinbases
|
||||
const CTxUndo &txundo = blockUndo.vtxundo[i-1];
|
||||
|
||||
@@ -93,10 +93,7 @@ bool CCoinsViewDB::GetSerial(const uint256 &serial) const {
|
||||
bool spent = false;
|
||||
bool read = db.Read(make_pair(DB_SERIAL, serial), spent);
|
||||
|
||||
// We should never read false from the database.
|
||||
assert(spent != read);
|
||||
|
||||
return spent;
|
||||
return read;
|
||||
}
|
||||
|
||||
bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) const {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -98,6 +98,7 @@ public:
|
||||
mutable CCriticalSection cs;
|
||||
std::map<uint256, CTxMemPoolEntry> mapTx;
|
||||
std::map<COutPoint, CInPoint> mapNextTx;
|
||||
std::map<uint256, const CTransaction*> mapSerials;
|
||||
std::map<uint256, std::pair<double, CAmount> > mapDeltas;
|
||||
|
||||
CTxMemPool(const CFeeRate& _minRelayFee);
|
||||
@@ -176,6 +177,7 @@ protected:
|
||||
|
||||
public:
|
||||
CCoinsViewMemPool(CCoinsView *baseIn, CTxMemPool &mempoolIn);
|
||||
bool GetSerial(const uint256 &txid) const;
|
||||
bool GetCoins(const uint256 &txid, CCoins &coins) const;
|
||||
bool HaveCoins(const uint256 &txid) const;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user