diff --git a/src/instantx.cpp b/src/instantx.cpp index dfe1c7d18e..80c725c646 100644 --- a/src/instantx.cpp +++ b/src/instantx.cpp @@ -22,6 +22,7 @@ std::map mapTxLockReq; std::map mapTxLockReqRejected; std::map mapTxLockVote; std::map mapTxLocks; +std::map mapLockedInputs; std::map mapUnknownVotes; //track votes with no tx for DOS int nCompleteTXLocks; @@ -101,6 +102,12 @@ void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream& tx.GetHash().ToString().c_str() ); + BOOST_FOREACH(const CTxIn& in, tx.vin){ + if(!mapLockedInputs.count(in.prevout)){ + mapLockedInputs.insert(make_pair(in.prevout, tx.GetHash())); + } + } + // resolve conflicts std::map::iterator i = mapTxLocks.find(tx.GetHash()); if (i != mapTxLocks.end()){ @@ -109,19 +116,8 @@ void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream& LogPrintf("ProcessMessageInstantX::txlreq - Found Existing Complete IX Lock\n"); CValidationState state; - bool fMissingInputs = false; DisconnectBlockAndInputs(state, tx); - - if (AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs)) - { - LogPrintf("ProcessMessageInstantX::txlreq - Transaction Lock Request : accepted (resolved) %s\n", - tx.GetHash().ToString().c_str() - ); - } else { - LogPrintf("ERROR: InstantX::ProcessConsensusVote - Transaction Lock Request : rejected (failed to resolve) %s\n", - tx.GetHash().ToString().c_str() - ); - } + mapTxLockReq.insert(make_pair(tx.GetHash(), tx)); } } @@ -294,25 +290,21 @@ bool ProcessConsensusVote(CConsensusVote& ctx) nCompleteTXLocks++; } + if(mapTxLockReq.count(ctx.txHash)){ + CTransaction& tx = mapTxLockReq[ctx.txHash]; + BOOST_FOREACH(const CTxIn& in, tx.vin){ + if(!mapLockedInputs.count(in.prevout)){ + mapLockedInputs.insert(make_pair(in.prevout, ctx.txHash)); + } + } + } + // resolve conflicts //if this tx lock was rejected, we need to remove the conflicting blocks if(mapTxLockReqRejected.count((*i).second.txHash)){ CValidationState state; - bool fMissingInputs = false; DisconnectBlockAndInputs(state, mapTxLockReqRejected[(*i).second.txHash]); - - if (AcceptToMemoryPool(mempool, state, mapTxLockReqRejected[(*i).second.txHash], true, &fMissingInputs)) - { - LogPrintf("ProcessMessageInstantX::txlreq - Transaction Lock Request : accepted (resolved) %s\n", - mapTxLockReqRejected[(*i).second.txHash].GetHash().ToString().c_str() - ); - - } else { - LogPrintf("ERROR: InstantX::ProcessConsensusVote - Transaction Lock Request : rejected (failed to resolve) %s\n", - mapTxLockReqRejected[(*i).second.txHash].GetHash().ToString().c_str() - ); - } } } return true; @@ -347,6 +339,17 @@ void CleanTransactionLocksList() while(it != mapTxLocks.end()) { if(GetTime() > it->second.nExpiration){ //keep them for an hour LogPrintf("Removing old transaction lock %s\n", it->second.txHash.ToString().c_str()); + + if(mapTxLockReq.count(it->second.txHash)){ + CTransaction& tx = mapTxLockReq[it->second.txHash]; + + BOOST_FOREACH(const CTxIn& in, tx.vin) + mapLockedInputs.erase(in.prevout); + + mapTxLockReq.erase(it->second.txHash); + mapTxLockReqRejected.erase(it->second.txHash); + } + mapTxLocks.erase(it++); } else { it++; diff --git a/src/instantx.h b/src/instantx.h index 67938c1db7..fd37324ef5 100644 --- a/src/instantx.h +++ b/src/instantx.h @@ -27,6 +27,7 @@ static const int MIN_INSTANTX_PROTO_VERSION = 70057; extern map mapTxLockReq; extern map mapTxLocks; +extern std::map mapLockedInputs; extern int nCompleteTXLocks; bool IsIXTXValid(const CTransaction& txCollateral); diff --git a/src/main.cpp b/src/main.cpp index d3c84bead6..d960cf467a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2512,7 +2512,7 @@ bool DisconnectBlockAndInputs(CValidationState &state, CTransaction txLock) if (!tx.IsCoinBase()){ BOOST_FOREACH(const CTxIn& in1, txLock.vin){ BOOST_FOREACH(const CTxIn& in2, tx.vin){ - if(in1 == in2) foundConflictingTx = true; + if(in1.prevout == in2.prevout) foundConflictingTx = true; } } } @@ -2531,67 +2531,10 @@ bool DisconnectBlockAndInputs(CValidationState &state, CTransaction txLock) LogPrintf("REORGANIZE: Disconnect Conflicting Blocks %lli blocks; %s..\n", vDisconnect.size(), pindexNew->GetBlockHash().ToString().c_str()); BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) { LogPrintf(" -- disconnect %s\n", pindex->GetBlockHash().ToString().c_str()); + DisconnectTip(state); } } - // Disconnect shorter branch - vector vResurrect; - BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) { - CBlock block; - if (!ReadBlockFromDisk(block, pindex)) - return state.Abort(_("Failed to read block")); - int64_t nStart = GetTimeMicros(); - if (!DisconnectBlock(block, state, pindex, view)) - return error("DisconnectBlockAndInputs/SetBestBlock() : DisconnectBlock %s failed", pindex->GetBlockHash().ToString().c_str()); - if (fBenchmark) - LogPrintf("- Disconnect: %.2fms\n", (GetTimeMicros() - nStart) * 0.001); - - // Queue memory transactions to resurrect. - // We only do this for blocks after the last checkpoint (reorganisation before that - // point should only happen with -reindex/-loadblock, or a misbehaving peer. - BOOST_FOREACH(const CTransaction& tx, block.vtx){ - if (!tx.IsCoinBase()){ - bool isConflict = false; - BOOST_FOREACH(const CTxIn& in1, txLock.vin){ - BOOST_FOREACH(const CTxIn& in2, tx.vin){ - if(in1 != in2) isConflict = true; - } - } - if(!isConflict) vResurrect.push_back(tx); - } - } - - } - - mempool.check(pcoinsTip); - // Update chainActive and related variables. - UpdateTip(pindexNew); - - // Resurrect memory transactions that were in the disconnected branch - BOOST_FOREACH(CTransaction& tx, vResurrect) { - // ignore validation errors in resurrected transactions - CValidationState stateDummy; - bool fMissingInputs; - list removed; - if (!AcceptToMemoryPool(mempool, stateDummy, tx, true, &fMissingInputs)) - mempool.remove(tx, removed, true); - } - - // Let wallets know transactions went from 1-confirmed to - // 0-confirmed or conflicted: - BOOST_FOREACH(const CTransaction &tx, vResurrect) { - SyncWithWallets(tx.GetHash(), tx, NULL); - } - - - // New best block - uint256 hashBestChain = pindexNew->GetBlockHash(); - - LogPrintf("DisconnectBlockAndInputs / SetBestChain: new best=%s height=%d tx=%lu date=%s progress=%f\n", - hashBestChain.ToString().c_str(), chainActive.Tip()->nHeight, (unsigned long)pindexNew->nChainTx, - DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()).c_str(), - Checkpoints::GuessVerificationProgress(chainActive.Tip())); - return true; } @@ -2883,27 +2826,17 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo // ----------- instantX transaction scanning ----------- - std::map::iterator it = mapTxLocks.begin(); - - while(it != mapTxLocks.end()) { - if(mapTxLockReq.count((*it).second.txHash)){ - CTransaction& tx = mapTxLockReq[(*it).second.txHash]; - for (unsigned int a = 0; a < tx.vin.size(); a++) { - for (unsigned int b = 0; b < block.vtx.size(); b++) { - //we found the locked tx in the block - if(tx.GetHash() == block.vtx[b].GetHash()) continue; - - //if there's a lock, look for conflicting inputs - for (unsigned int c = 0; c < block.vtx[b].vin.size(); c++) { - if(tx.vin[a].prevout == block.vtx[b].vin[c].prevout) { - return state.DoS(100, error("CheckBlock() : found conflicting transaction with transaction lock"), - REJECT_INVALID, "conflicting-tx-ix"); - } + BOOST_FOREACH(const CTransaction& tx, block.vtx){ + if (!tx.IsCoinBase()){ + BOOST_FOREACH(const CTxIn& in, tx.vin){ + if(mapLockedInputs.count(in.prevout)){ + if(mapLockedInputs[in.prevout] != tx.GetHash()){ + return state.DoS(100, error("CheckBlock() : found conflicting transaction with transaction lock"), + REJECT_INVALID, "conflicting-tx-ix"); } } } } - it++; } @@ -4558,6 +4491,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) CBlock block; vRecv >> block; + LogPrint("net", "received block %s\n", block.GetHash().ToString()); // block.print();