Conflict handling for ProRegTx in mempool

This commit is contained in:
Alexander Block 2018-02-14 14:42:06 +01:00
parent c772423468
commit cdd723ede6
3 changed files with 77 additions and 0 deletions

View File

@ -21,6 +21,9 @@
#include "version.h"
#include "hash.h"
#include "evo/specialtx.h"
#include "evo/providertx.h"
CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee,
int64_t _nTime, double _entryPriority, unsigned int _entryHeight,
CAmount _inChainInputValue,
@ -438,6 +441,16 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
vTxHashes.emplace_back(hash, newit);
newit->vTxHashesIdx = vTxHashes.size() - 1;
if (tx.nType == TRANSACTION_PROVIDER_REGISTER) {
CProRegTx proTx;
if (!GetTxPayload(tx, proTx)) {
assert(false);
}
mapProTxRegisterAddresses.emplace(proTx.addr, tx.GetHash());
mapProTxPubKeyIDs.emplace(proTx.keyIDOwner, tx.GetHash());
mapProTxPubKeyIDs.emplace(proTx.keyIDOperator, tx.GetHash());
}
return true;
}
@ -613,6 +626,16 @@ void CTxMemPool::removeUnchecked(txiter it, MemPoolRemovalReason reason)
} else
vTxHashes.clear();
if (it->GetTx().nVersion >= 3 && it->GetTx().nType == TRANSACTION_PROVIDER_REGISTER) {
CProRegTx proTx;
if (!GetTxPayload(it->GetTx(), proTx)) {
assert(false);
}
mapProTxRegisterAddresses.erase(proTx.addr);
mapProTxPubKeyIDs.erase(proTx.keyIDOwner);
mapProTxPubKeyIDs.erase(proTx.keyIDOperator);
}
totalTxSize -= it->GetTxSize();
cachedInnerUsage -= it->DynamicMemoryUsage();
cachedInnerUsage -= memusage::DynamicUsage(mapLinks[it].parents) + memusage::DynamicUsage(mapLinks[it].children);
@ -739,6 +762,36 @@ void CTxMemPool::removeConflicts(const CTransaction &tx)
}
}
void CTxMemPool::removeProTxConflicts(const CTransaction &tx)
{
if (tx.nType != TRANSACTION_PROVIDER_REGISTER)
return;
CProRegTx proTx;
if (!GetTxPayload(tx, proTx)) {
assert(false);
}
if (mapProTxRegisterAddresses.count(proTx.addr)) {
uint256 conflictHash = mapProTxRegisterAddresses[proTx.addr];
if (conflictHash != tx.GetHash() && mapTx.count(conflictHash)) {
removeRecursive(mapTx.find(conflictHash)->GetTx(), MemPoolRemovalReason::CONFLICT);
}
}
if (mapProTxPubKeyIDs.count(proTx.keyIDOwner)) {
uint256 conflictHash = mapProTxPubKeyIDs[proTx.keyIDOwner];
if (conflictHash != tx.GetHash() && mapTx.count(conflictHash)) {
removeRecursive(mapTx.find(conflictHash)->GetTx(), MemPoolRemovalReason::CONFLICT);
}
}
if (mapProTxPubKeyIDs.count(proTx.keyIDOperator)) {
uint256 conflictHash = mapProTxPubKeyIDs[proTx.keyIDOperator];
if (conflictHash != tx.GetHash() && mapTx.count(conflictHash)) {
removeRecursive(mapTx.find(conflictHash)->GetTx(), MemPoolRemovalReason::CONFLICT);
}
}
}
/**
* Called when a block is connected. Removes from mempool and updates the miner fee estimator.
*/
@ -765,6 +818,7 @@ void CTxMemPool::removeForBlock(const std::vector<CTransactionRef>& vtx, unsigne
RemoveStaged(stage, true, MemPoolRemovalReason::BLOCK);
}
removeConflicts(*tx);
removeProTxConflicts(*tx);
ClearPrioritisation(tx->GetHash());
}
lastRollingFeeUpdate = GetTime();
@ -776,6 +830,8 @@ void CTxMemPool::_clear()
mapLinks.clear();
mapTx.clear();
mapNextTx.clear();
mapProTxRegisterAddresses.clear();
mapProTxPubKeyIDs.clear();
totalTxSize = 0;
cachedInnerUsage = 0;
lastRollingFeeUpdate = GetTime();
@ -1013,6 +1069,16 @@ TxMempoolInfo CTxMemPool::info(const uint256& hash) const
return GetInfo(i);
}
bool CTxMemPool::existsProviderTxConflict(const CTransaction &tx) const {
LOCK(cs);
if (tx.nVersion < 3 || tx.nType != TRANSACTION_PROVIDER_REGISTER)
return false;
CProRegTx proTx;
if (!GetTxPayload(tx, proTx))
assert(false);
return mapProTxRegisterAddresses.count(proTx.addr) || mapProTxPubKeyIDs.count(proTx.keyIDOwner) || mapProTxPubKeyIDs.count(proTx.keyIDOperator);
}
CFeeRate CTxMemPool::estimateFee(int nBlocks) const
{
LOCK(cs);

View File

@ -21,6 +21,7 @@
#include "primitives/transaction.h"
#include "sync.h"
#include "random.h"
#include "netaddress.h"
#undef foreach
#include "boost/multi_index_container.hpp"
@ -534,6 +535,9 @@ private:
typedef std::map<uint256, std::vector<CSpentIndexKey> > mapSpentIndexInserted;
mapSpentIndexInserted mapSpentInserted;
std::map<CService, uint256> mapProTxRegisterAddresses;
std::map<CKeyID, uint256> mapProTxPubKeyIDs;
void UpdateParent(txiter entry, txiter parent, bool add);
void UpdateChild(txiter entry, txiter child, bool add);
@ -576,6 +580,7 @@ public:
void removeRecursive(const CTransaction &tx, MemPoolRemovalReason reason = MemPoolRemovalReason::UNKNOWN);
void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags);
void removeConflicts(const CTransaction &tx);
void removeProTxConflicts(const CTransaction &tx);
void removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight);
void clear();
@ -684,6 +689,8 @@ public:
TxMempoolInfo info(const uint256& hash) const;
std::vector<TxMempoolInfo> infoAll() const;
bool existsProviderTxConflict(const CTransaction &tx) const;
/** Estimate fee rate needed to get into the next nBlocks
* If no answer can be given at nBlocks, return an estimate
* at the lowest number of blocks where one can be given

View File

@ -650,6 +650,10 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
if (fRequireStandard && !IsStandardTx(tx, reason))
return state.DoS(0, false, REJECT_NONSTANDARD, reason);
if (pool.existsProviderTxConflict(tx)) {
return state.DoS(0, false, REJECT_DUPLICATE, "protx-dup");
}
// Only accept nLockTime-using transactions that can be mined in the next
// block; we don't want our mempool filled up with transactions that can't
// be mined yet.