mirror of
https://github.com/dashpay/dash.git
synced 2024-12-27 04:52:59 +01:00
improved conflict resolution
This commit is contained in:
parent
d13de27d57
commit
712eb7e9d9
@ -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++;
|
||||
|
@ -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);
|
||||
|
86
src/main.cpp
86
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<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();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user