mirror of
https://github.com/dashpay/dash.git
synced 2024-12-28 13:32:47 +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, CTransaction> mapTxLockReqRejected;
|
||||||
std::map<uint256, int> mapTxLockVote;
|
std::map<uint256, int> mapTxLockVote;
|
||||||
std::map<uint256, CTransactionLock> mapTxLocks;
|
std::map<uint256, CTransactionLock> mapTxLocks;
|
||||||
|
std::map<COutPoint, uint256> mapLockedInputs;
|
||||||
std::map<uint256, int64_t> mapUnknownVotes; //track votes with no tx for DOS
|
std::map<uint256, int64_t> mapUnknownVotes; //track votes with no tx for DOS
|
||||||
int nCompleteTXLocks;
|
int nCompleteTXLocks;
|
||||||
|
|
||||||
@ -101,6 +102,12 @@ void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream&
|
|||||||
tx.GetHash().ToString().c_str()
|
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
|
// resolve conflicts
|
||||||
std::map<uint256, CTransactionLock>::iterator i = mapTxLocks.find(tx.GetHash());
|
std::map<uint256, CTransactionLock>::iterator i = mapTxLocks.find(tx.GetHash());
|
||||||
if (i != mapTxLocks.end()){
|
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");
|
LogPrintf("ProcessMessageInstantX::txlreq - Found Existing Complete IX Lock\n");
|
||||||
|
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
bool fMissingInputs = false;
|
|
||||||
DisconnectBlockAndInputs(state, tx);
|
DisconnectBlockAndInputs(state, tx);
|
||||||
|
mapTxLockReq.insert(make_pair(tx.GetHash(), 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()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,25 +290,21 @@ bool ProcessConsensusVote(CConsensusVote& ctx)
|
|||||||
nCompleteTXLocks++;
|
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
|
// resolve conflicts
|
||||||
|
|
||||||
//if this tx lock was rejected, we need to remove the conflicting blocks
|
//if this tx lock was rejected, we need to remove the conflicting blocks
|
||||||
if(mapTxLockReqRejected.count((*i).second.txHash)){
|
if(mapTxLockReqRejected.count((*i).second.txHash)){
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
bool fMissingInputs = false;
|
|
||||||
DisconnectBlockAndInputs(state, mapTxLockReqRejected[(*i).second.txHash]);
|
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;
|
return true;
|
||||||
@ -347,6 +339,17 @@ void CleanTransactionLocksList()
|
|||||||
while(it != mapTxLocks.end()) {
|
while(it != mapTxLocks.end()) {
|
||||||
if(GetTime() > it->second.nExpiration){ //keep them for an hour
|
if(GetTime() > it->second.nExpiration){ //keep them for an hour
|
||||||
LogPrintf("Removing old transaction lock %s\n", it->second.txHash.ToString().c_str());
|
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++);
|
mapTxLocks.erase(it++);
|
||||||
} else {
|
} else {
|
||||||
it++;
|
it++;
|
||||||
|
@ -27,6 +27,7 @@ static const int MIN_INSTANTX_PROTO_VERSION = 70057;
|
|||||||
|
|
||||||
extern map<uint256, CTransaction> mapTxLockReq;
|
extern map<uint256, CTransaction> mapTxLockReq;
|
||||||
extern map<uint256, CTransactionLock> mapTxLocks;
|
extern map<uint256, CTransactionLock> mapTxLocks;
|
||||||
|
extern std::map<COutPoint, uint256> mapLockedInputs;
|
||||||
extern int nCompleteTXLocks;
|
extern int nCompleteTXLocks;
|
||||||
|
|
||||||
bool IsIXTXValid(const CTransaction& txCollateral);
|
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()){
|
if (!tx.IsCoinBase()){
|
||||||
BOOST_FOREACH(const CTxIn& in1, txLock.vin){
|
BOOST_FOREACH(const CTxIn& in1, txLock.vin){
|
||||||
BOOST_FOREACH(const CTxIn& in2, tx.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());
|
LogPrintf("REORGANIZE: Disconnect Conflicting Blocks %lli blocks; %s..\n", vDisconnect.size(), pindexNew->GetBlockHash().ToString().c_str());
|
||||||
BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) {
|
BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) {
|
||||||
LogPrintf(" -- disconnect %s\n", pindex->GetBlockHash().ToString().c_str());
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2883,27 +2826,17 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
|
|||||||
|
|
||||||
// ----------- instantX transaction scanning -----------
|
// ----------- instantX transaction scanning -----------
|
||||||
|
|
||||||
std::map<uint256, CTransactionLock>::iterator it = mapTxLocks.begin();
|
BOOST_FOREACH(const CTransaction& tx, block.vtx){
|
||||||
|
if (!tx.IsCoinBase()){
|
||||||
while(it != mapTxLocks.end()) {
|
BOOST_FOREACH(const CTxIn& in, tx.vin){
|
||||||
if(mapTxLockReq.count((*it).second.txHash)){
|
if(mapLockedInputs.count(in.prevout)){
|
||||||
CTransaction& tx = mapTxLockReq[(*it).second.txHash];
|
if(mapLockedInputs[in.prevout] != tx.GetHash()){
|
||||||
for (unsigned int a = 0; a < tx.vin.size(); a++) {
|
return state.DoS(100, error("CheckBlock() : found conflicting transaction with transaction lock"),
|
||||||
for (unsigned int b = 0; b < block.vtx.size(); b++) {
|
REJECT_INVALID, "conflicting-tx-ix");
|
||||||
//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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
it++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -4558,6 +4491,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
|||||||
CBlock block;
|
CBlock block;
|
||||||
vRecv >> block;
|
vRecv >> block;
|
||||||
|
|
||||||
|
|
||||||
LogPrint("net", "received block %s\n", block.GetHash().ToString());
|
LogPrint("net", "received block %s\n", block.GetHash().ToString());
|
||||||
// block.print();
|
// block.print();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user