cancel out conflicting locks

This commit is contained in:
Evan Duffield 2015-02-05 09:48:57 -07:00
parent c3b92a7103
commit 97d73a72b5
3 changed files with 53 additions and 28 deletions

View File

@ -104,11 +104,13 @@ void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream&
if (i != mapTxLocks.end()){ if (i != mapTxLocks.end()){
//we only care if we have a complete tx lock //we only care if we have a complete tx lock
if((*i).second.CountSignatures() >= INSTANTX_SIGNATURES_REQUIRED){ if((*i).second.CountSignatures() >= INSTANTX_SIGNATURES_REQUIRED){
LogPrintf("ProcessMessageInstantX::txlreq - Found Existing Complete IX Lock\n"); if(!CheckForConflictingLocks(tx)){
LogPrintf("ProcessMessageInstantX::txlreq - Found Existing Complete IX Lock\n");
CValidationState state; CValidationState state;
DisconnectBlockAndInputs(state, tx); DisconnectBlockAndInputs(state, tx);
mapTxLockReq.insert(make_pair(tx.GetHash(), tx)); mapTxLockReq.insert(make_pair(tx.GetHash(), tx));
}
} }
} }
@ -229,7 +231,7 @@ int64_t CreateNewLock(CTransaction tx)
CTransactionLock newLock; CTransactionLock newLock;
newLock.nBlockHeight = nBlockHeight; newLock.nBlockHeight = nBlockHeight;
newLock.nExpiration = GetTime()+(60*60); newLock.nExpiration = GetTime()+(60*15); //locks expire after 15 minutes (6 confirmations)
newLock.nTimeout = GetTime()+(60*5); newLock.nTimeout = GetTime()+(60*5);
newLock.txHash = tx.GetHash(); newLock.txHash = tx.GetHash();
mapTxLocks.insert(make_pair(tx.GetHash(), newLock)); mapTxLocks.insert(make_pair(tx.GetHash(), newLock));
@ -318,29 +320,32 @@ bool ProcessConsensusVote(CConsensusVote& ctx)
if((*i).second.CountSignatures() >= INSTANTX_SIGNATURES_REQUIRED){ if((*i).second.CountSignatures() >= INSTANTX_SIGNATURES_REQUIRED){
if(fDebug) LogPrintf("InstantX::ProcessConsensusVote - Transaction Lock Is Complete %s !\n", (*i).second.GetHash().ToString().c_str()); if(fDebug) LogPrintf("InstantX::ProcessConsensusVote - Transaction Lock Is Complete %s !\n", (*i).second.GetHash().ToString().c_str());
#ifdef ENABLE_WALLET CTransaction& tx = mapTxLockReq[ctx.txHash];
if(pwalletMain){ if(!CheckForConflictingLocks(tx)){
if(pwalletMain->UpdatedTransaction((*i).second.txHash)){
nCompleteTXLocks++;
}
}
#endif
if(mapTxLockReq.count(ctx.txHash)){ #ifdef ENABLE_WALLET
CTransaction& tx = mapTxLockReq[ctx.txHash]; if(pwalletMain){
BOOST_FOREACH(const CTxIn& in, tx.vin){ if(pwalletMain->UpdatedTransaction((*i).second.txHash)){
if(!mapLockedInputs.count(in.prevout)){ nCompleteTXLocks++;
mapLockedInputs.insert(make_pair(in.prevout, ctx.txHash));
} }
} }
} #endif
// resolve conflicts if(mapTxLockReq.count(ctx.txHash)){
BOOST_FOREACH(const CTxIn& in, tx.vin){
if(!mapLockedInputs.count(in.prevout)){
mapLockedInputs.insert(make_pair(in.prevout, ctx.txHash));
}
}
}
//if this tx lock was rejected, we need to remove the conflicting blocks // resolve conflicts
if(mapTxLockReqRejected.count((*i).second.txHash)){
CValidationState state; //if this tx lock was rejected, we need to remove the conflicting blocks
DisconnectBlockAndInputs(state, mapTxLockReqRejected[(*i).second.txHash]); if(mapTxLockReqRejected.count((*i).second.txHash)){
CValidationState state;
DisconnectBlockAndInputs(state, mapTxLockReqRejected[(*i).second.txHash]);
}
} }
} }
return true; return true;
@ -350,6 +355,28 @@ bool ProcessConsensusVote(CConsensusVote& ctx)
return false; return false;
} }
bool CheckForConflictingLocks(CTransaction& tx)
{
/*
It's possible (very unlikely though) to get 2 conflicting transaction locks approved by the network.
In that case, they will cancel each other out.
Blocks could have been rejected during this time, which is OK. After they cancel out, the client will
rescan the blocks and find they're acceptable and then take the chain with the most work.
*/
BOOST_FOREACH(const CTxIn& in, tx.vin){
if(mapLockedInputs.count(in.prevout)){
if(mapLockedInputs[in.prevout] != tx.GetHash()){
LogPrintf("InstantX::CheckForConflictingLocks - found two complete conflicting locks - removing both. %s %s", tx.GetHash().ToString().c_str(), mapLockedInputs[in.prevout].ToString().c_str());
if(mapTxLocks.count(tx.GetHash())) mapTxLocks[tx.GetHash()].nExpiration = GetTime();
if(mapTxLocks.count(mapLockedInputs[in.prevout])) mapTxLocks[mapLockedInputs[in.prevout]].nExpiration = GetTime();
return true;
}
}
}
return false;
}
int64_t GetAverageVoteTime() int64_t GetAverageVoteTime()
{ {

View File

@ -35,6 +35,9 @@ int64_t CreateNewLock(CTransaction tx);
bool IsIXTXValid(const CTransaction& txCollateral); bool IsIXTXValid(const CTransaction& txCollateral);
// if two conflicting locks are approved by the network, they will cancel out
bool CheckForConflictingLocks(CTransaction& tx);
void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream& vRecv); void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
//check if we need to vote on this transaction //check if we need to vote on this transaction

View File

@ -2823,11 +2823,6 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
// ----------- instantX transaction scanning ----------- // ----------- instantX transaction scanning -----------
/*
block-level scanning is working below, but we need a blockchain
based management system for storing the active masternodes. Otherwise
small inconsistances can lead to forks.
*/
BOOST_FOREACH(const CTransaction& tx, block.vtx){ BOOST_FOREACH(const CTransaction& tx, block.vtx){
if (!tx.IsCoinBase()){ if (!tx.IsCoinBase()){