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,6 +104,7 @@ 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){
if(!CheckForConflictingLocks(tx)){
LogPrintf("ProcessMessageInstantX::txlreq - Found Existing Complete IX Lock\n"); LogPrintf("ProcessMessageInstantX::txlreq - Found Existing Complete IX Lock\n");
CValidationState state; CValidationState state;
@ -111,6 +112,7 @@ void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream&
mapTxLockReq.insert(make_pair(tx.GetHash(), tx)); mapTxLockReq.insert(make_pair(tx.GetHash(), tx));
} }
} }
}
return; return;
} }
@ -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,6 +320,9 @@ 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());
CTransaction& tx = mapTxLockReq[ctx.txHash];
if(!CheckForConflictingLocks(tx)){
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
if(pwalletMain){ if(pwalletMain){
if(pwalletMain->UpdatedTransaction((*i).second.txHash)){ if(pwalletMain->UpdatedTransaction((*i).second.txHash)){
@ -327,7 +332,6 @@ bool ProcessConsensusVote(CConsensusVote& ctx)
#endif #endif
if(mapTxLockReq.count(ctx.txHash)){ if(mapTxLockReq.count(ctx.txHash)){
CTransaction& tx = mapTxLockReq[ctx.txHash];
BOOST_FOREACH(const CTxIn& in, tx.vin){ BOOST_FOREACH(const CTxIn& in, tx.vin){
if(!mapLockedInputs.count(in.prevout)){ if(!mapLockedInputs.count(in.prevout)){
mapLockedInputs.insert(make_pair(in.prevout, ctx.txHash)); mapLockedInputs.insert(make_pair(in.prevout, ctx.txHash));
@ -343,6 +347,7 @@ bool ProcessConsensusVote(CConsensusVote& ctx)
DisconnectBlockAndInputs(state, mapTxLockReqRejected[(*i).second.txHash]); 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()){