improved conflict resolution

This commit is contained in:
Evan Duffield 2015-02-04 13:20:13 -07:00
parent d13de27d57
commit 712eb7e9d9
3 changed files with 39 additions and 101 deletions

View File

@ -22,6 +22,7 @@ std::map<uint256, CTransaction> mapTxLockReq;
std::map<uint256, CTransaction> mapTxLockReqRejected;
std::map<uint256, int> mapTxLockVote;
std::map<uint256, CTransactionLock> mapTxLocks;
std::map<COutPoint, uint256> mapLockedInputs;
std::map<uint256, int64_t> 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<uint256, CTransactionLock>::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++;

View File

@ -27,6 +27,7 @@ static const int MIN_INSTANTX_PROTO_VERSION = 70057;
extern map<uint256, CTransaction> mapTxLockReq;
extern map<uint256, CTransactionLock> mapTxLocks;
extern std::map<COutPoint, uint256> mapLockedInputs;
extern int nCompleteTXLocks;
bool IsIXTXValid(const CTransaction& txCollateral);

View File

@ -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<CTransaction> 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<CTransaction> 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<uint256, CTransactionLock>::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();