Skip to content

Commit

Permalink
Autoremove Failed Transactions from Mempool
Browse files Browse the repository at this point in the history
If two or more transactions share the same input and one of them gets
into a block, the others should be invalidated from the mempool
(see Bitcoin commit 231b399952fd620ee0f72b1947024dba9651630d).
Non-working SPV related code also removed.
  • Loading branch information
ghostlander committed Jul 19, 2017
1 parent 66999bd commit 1d42157
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 72 deletions.
6 changes: 0 additions & 6 deletions src/db.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -381,20 +381,17 @@ void CDBEnv::Flush(bool fShutdown)

bool CTxDB::ReadTxIndex(uint256 hash, CTxIndex& txindex)
{
assert(!fClient);
txindex.SetNull();
return Read(make_pair(string("tx"), hash), txindex);
}

bool CTxDB::UpdateTxIndex(uint256 hash, const CTxIndex& txindex)
{
assert(!fClient);
return Write(make_pair(string("tx"), hash), txindex);
}

bool CTxDB::AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight)
{
assert(!fClient);

// Add to tx index
uint256 hash = tx.GetHash();
Expand All @@ -404,21 +401,18 @@ bool CTxDB::AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeigh

bool CTxDB::EraseTxIndex(const CTransaction& tx)
{
assert(!fClient);
uint256 hash = tx.GetHash();

return Erase(make_pair(string("tx"), hash));
}

bool CTxDB::ContainsTx(uint256 hash)
{
assert(!fClient);
return Exists(make_pair(string("tx"), hash));
}

bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex)
{
assert(!fClient);
tx.SetNull();
if (!ReadTxIndex(hash, txindex))
return false;
Expand Down
122 changes: 62 additions & 60 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -384,46 +384,36 @@ CTransaction::GetLegacySigOpCount() const
}


int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
{
if (fClient)
{
if (hashBlock == 0)
return 0;
int CMerkleTx::SetMerkleBranch(const CBlock *pblock) {

CBlock blockTmp;
if(pblock == NULL) {
// Load the block this tx is in
CTxIndex txindex;
if(!CTxDB("r").ReadTxIndex(GetHash(), txindex))
return(0);
if(!blockTmp.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos))
return(0);
pblock = &blockTmp;
}
else
{
CBlock blockTmp;
if (pblock == NULL)
{
// Load the block this tx is in
CTxIndex txindex;
if (!CTxDB("r").ReadTxIndex(GetHash(), txindex))
return 0;
if (!blockTmp.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos))
return 0;
pblock = &blockTmp;
}

// Update the tx's hashBlock
hashBlock = pblock->GetHash();
// Update the tx's hashBlock
hashBlock = pblock->GetHash();

// Locate the transaction
for (nIndex = 0; nIndex < (int)pblock->vtx.size(); nIndex++)
if (pblock->vtx[nIndex] == *(CTransaction*)this)
break;
if (nIndex == (int)pblock->vtx.size())
{
vMerkleBranch.clear();
nIndex = -1;
printf("ERROR: SetMerkleBranch() : couldn't find tx in block\n");
return 0;
}
// Locate the transaction
for(nIndex = 0; nIndex < (int)pblock->vtx.size(); nIndex++)
if(pblock->vtx[nIndex] == *(CTransaction *)this) break;

// Fill in merkle branch
vMerkleBranch = pblock->GetMerkleBranch(nIndex);
if(nIndex == (int)pblock->vtx.size()) {
vMerkleBranch.clear();
nIndex = -1;
printf("ERROR: SetMerkleBranch() : couldn't find tx in block\n");
return(0);
}

// Fill in merkle branch
vMerkleBranch = pblock->GetMerkleBranch(nIndex);

// Is the tx in a block that's in the main chain
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
if (mi == mapBlockIndex.end())
Expand Down Expand Up @@ -652,22 +642,41 @@ bool CTxMemPool::addUnchecked(const uint256& hash, CTransaction &tx)
return true;
}

/* Removes a transaction from the memory pool */
bool CTxMemPool::remove(const CTransaction &tx, bool fRecursive) {

bool CTxMemPool::remove(CTransaction &tx)
{
// Remove transaction from memory pool
{
LOCK(cs);
uint256 hash = tx.GetHash();
if (mapTx.count(hash))
{
BOOST_FOREACH(const CTxIn& txin, tx.vin)
mapNextTx.erase(txin.prevout);
mapTx.erase(hash);
nTransactionsUpdated++;
LOCK(cs);
uint256 hash = tx.GetHash();
if(mapTx.count(hash)) {
if(fRecursive) {
uint i;
for(i = 0; i < tx.vout.size(); i++) {
std::map<COutPoint, CInPoint>::iterator it = mapNextTx.find(COutPoint(hash, i));
if(it != mapNextTx.end())
remove(*it->second.ptx, true);
}
}
BOOST_FOREACH(const CTxIn &txin, tx.vin)
mapNextTx.erase(txin.prevout);
mapTx.erase(hash);
nTransactionsUpdated++;
}
return true;
return(true);
}

/* Removes transactions from the memory pool which depend on inputs of this transaction */
bool CTxMemPool::removeConflicts(const CTransaction &tx) {

LOCK(cs);
BOOST_FOREACH(const CTxIn &txin, tx.vin) {
std::map<COutPoint, CInPoint>::iterator it = mapNextTx.find(txin.prevout);
if(it != mapNextTx.end()) {
const CTransaction &txConflict = *it->second.ptx;
if(txConflict != tx)
remove(txConflict, true);
}
}
return(true);
}

void CTxMemPool::queryHashes(std::vector<uint256>& vtxid)
Expand Down Expand Up @@ -721,18 +730,9 @@ int CMerkleTx::GetBlocksToMaturity() const
}


bool CMerkleTx::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs)
{
if (fClient)
{
if (!IsInMainChain() && !ClientConnectInputs())
return false;
return CTransaction::AcceptToMemoryPool(txdb, false);
}
else
{
return CTransaction::AcceptToMemoryPool(txdb, fCheckInputs);
}
bool CMerkleTx::AcceptToMemoryPool(CTxDB &txdb, bool fCheckInputs) {

return(CTransaction::AcceptToMemoryPool(txdb, fCheckInputs));
}

bool CMerkleTx::AcceptToMemoryPool()
Expand Down Expand Up @@ -1584,8 +1584,10 @@ bool static Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
tx.AcceptToMemoryPool(txdb, false);

// Delete redundant memory transactions that are in the connected branch
BOOST_FOREACH(CTransaction& tx, vDelete)
BOOST_FOREACH(CTransaction &tx, vDelete) {
mempool.remove(tx);
mempool.removeConflicts(tx);
}

printf("REORGANIZE: done\n");

Expand Down
3 changes: 2 additions & 1 deletion src/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -1724,7 +1724,8 @@ class CTxMemPool
bool accept(CTxDB& txdb, CTransaction &tx,
bool fCheckInputs, bool* pfMissingInputs);
bool addUnchecked(const uint256& hash, CTransaction &tx);
bool remove(CTransaction &tx);
bool remove(const CTransaction &tx, bool fRecursive = false);
bool removeConflicts(const CTransaction &tx);
void queryHashes(std::vector<uint256>& vtxid);

unsigned long size()
Expand Down
3 changes: 1 addition & 2 deletions src/net.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,9 @@ struct LocalServiceInfo {
//
// Global state variables
//
bool fClient = false;
bool fDiscover = true;
bool fUseUPnP = false;
uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK);
uint64 nLocalServices = NODE_NETWORK;
static CCriticalSection cs_mapLocalHost;
static map<CNetAddr, LocalServiceInfo> mapLocalHost;
static bool vfReachable[NET_MAX] = {};
Expand Down
1 change: 0 additions & 1 deletion src/net.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ enum threadId
THREAD_MAX
};

extern bool fClient;
extern bool fDiscover;
extern bool fUseUPnP;
extern uint64 nLocalServices;
Expand Down
3 changes: 1 addition & 2 deletions src/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -653,8 +653,7 @@ void CWalletTx::AddSupportingTransactions(CTxDB& txdb)
{
tx = *mapWalletPrev[hash];
}
else if (!fClient && txdb.ReadDiskTx(hash, tx))
{
else if(txdb.ReadDiskTx(hash, tx)) {
;
}
else
Expand Down

0 comments on commit 1d42157

Please sign in to comment.