Skip to content

Commit

Permalink
Track operator key changes in mempool and handle conflicts (#2540)
Browse files Browse the repository at this point in the history
* Track ProTx operator key changes in mempool

* Remove ProTx conflicts from mempool when ProUpRegTx or ProUpRevTx changed keys

* Only allow one operator key change per MN in in mempool
  • Loading branch information
codablock authored Dec 10, 2018
1 parent 88f7bf0 commit 5830353
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 0 deletions.
79 changes: 79 additions & 0 deletions src/txmempool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -472,13 +472,26 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
}
mapProTxRefs.emplace(proTx.proTxHash, tx.GetHash());
mapProTxBlsPubKeyHashes.emplace(proTx.pubKeyOperator.GetHash(), tx.GetHash());

auto dmn = deterministicMNManager->GetListAtChainTip().GetMN(proTx.proTxHash);
assert(dmn); // we should never get such a ProTx into the mempool
newit->validForProTxKey = ::SerializeHash(dmn->pdmnState->pubKeyOperator);
if (dmn->pdmnState->pubKeyOperator != proTx.pubKeyOperator) {
newit->isKeyChangeProTx = true;
}
} else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_REVOKE) {
CProUpRevTx proTx;
if (!GetTxPayload(tx, proTx)) {
LogPrintf("%s: ERROR: Invalid transaction payload, tx: %s", __func__, tx.ToString());
return false;
}
mapProTxRefs.emplace(proTx.proTxHash, tx.GetHash());
auto dmn = deterministicMNManager->GetListAtChainTip().GetMN(proTx.proTxHash);
assert(dmn); // we should never get such a ProTx into the mempool
newit->validForProTxKey = ::SerializeHash(dmn->pdmnState->pubKeyOperator);
if (dmn->pdmnState->pubKeyOperator != CBLSPublicKey()) {
newit->isKeyChangeProTx = true;
}
}

return true;
Expand Down Expand Up @@ -893,6 +906,24 @@ void CTxMemPool::removeProTxSpentCollateralConflicts(const CTransaction &tx)
}
}

void CTxMemPool::removeProTxKeyChangedConflicts(const CTransaction &tx, const uint256& proTxHash, const uint256& newKeyHash)
{
std::set<uint256> conflictingTxs;
for (auto its = mapProTxRefs.equal_range(proTxHash); its.first != its.second; ++its.first) {
auto txit = mapTx.find(its.first->second);
if (txit == mapTx.end()) {
continue;
}
if (txit->validForProTxKey != newKeyHash) {
conflictingTxs.emplace(txit->GetTx().GetHash());
}
}
for (const auto& txHash : conflictingTxs) {
auto& tx = mapTx.find(txHash)->GetTx();
removeRecursive(tx, MemPoolRemovalReason::CONFLICT);
}
}

void CTxMemPool::removeProTxConflicts(const CTransaction &tx)
{
removeProTxSpentCollateralConflicts(tx);
Expand Down Expand Up @@ -936,6 +967,15 @@ void CTxMemPool::removeProTxConflicts(const CTransaction &tx)
}

removeProTxPubKeyConflicts(tx, proTx.pubKeyOperator);
removeProTxKeyChangedConflicts(tx, proTx.proTxHash, ::SerializeHash(proTx.pubKeyOperator));
} else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_REVOKE) {
CProUpRevTx proTx;
if (!GetTxPayload(tx, proTx)) {
LogPrintf("%s: ERROR: Invalid transaction payload, tx: %s", __func__, tx.ToString());
return;
}

removeProTxKeyChangedConflicts(tx, proTx.proTxHash, ::SerializeHash(CBLSPublicKey()));
}
}

Expand Down Expand Up @@ -1218,6 +1258,20 @@ TxMempoolInfo CTxMemPool::info(const uint256& hash) const

bool CTxMemPool::existsProviderTxConflict(const CTransaction &tx) const {
LOCK(cs);

auto hasKeyChangeInMempool = [&](const uint256& proTxHash) {
for (auto its = mapProTxRefs.equal_range(proTxHash); its.first != its.second; ++its.first) {
auto txit = mapTx.find(its.first->second);
if (txit == mapTx.end()) {
continue;
}
if (txit->isKeyChangeProTx) {
return true;
}
}
return false;
};

if (tx.nType == TRANSACTION_PROVIDER_REGISTER) {
CProRegTx proTx;
if (!GetTxPayload(tx, proTx)) {
Expand All @@ -1243,8 +1297,33 @@ bool CTxMemPool::existsProviderTxConflict(const CTransaction &tx) const {
LogPrintf("%s: ERROR: Invalid transaction payload, tx: %s", __func__, tx.ToString());
return true; // i.e. can't decode payload == conflict
}

// only allow one operator key change in the mempool
auto dmn = deterministicMNManager->GetListAtChainTip().GetMN(proTx.proTxHash);
assert(dmn); // this method should only be called with validated ProTxs
if (dmn->pdmnState->pubKeyOperator != proTx.pubKeyOperator) {
if (hasKeyChangeInMempool(proTx.proTxHash)) {
return true;
}
}

auto it = mapProTxBlsPubKeyHashes.find(proTx.pubKeyOperator.GetHash());
return it != mapProTxBlsPubKeyHashes.end() && it->second != proTx.proTxHash;
} else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_REVOKE) {
CProUpRevTx proTx;
if (!GetTxPayload(tx, proTx)) {
LogPrintf("%s: ERROR: Invalid transaction payload, tx: %s", __func__, tx.ToString());
return true; // i.e. can't decode payload == conflict
}

// only allow one operator key change in the mempool
auto dmn = deterministicMNManager->GetListAtChainTip().GetMN(proTx.proTxHash);
assert(dmn); // this method should only be called with validated ProTxs
if (dmn->pdmnState->pubKeyOperator != CBLSPublicKey()) {
if (hasKeyChangeInMempool(proTx.proTxHash)) {
return true;
}
}
}
return false;
}
Expand Down
5 changes: 5 additions & 0 deletions src/txmempool.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ class CTxMemPoolEntry
unsigned int GetSigOpCountWithAncestors() const { return nSigOpCountWithAncestors; }

mutable size_t vTxHashesIdx; //!< Index in mempool's vTxHashes

// If this is a proTx, this will be the hash of the key for which this ProTx was valid
mutable uint256 validForProTxKey;
mutable bool isKeyChangeProTx{false};
};

// Helpers for modifying CTxMemPool::mapTx, which is a boost multi_index.
Expand Down Expand Up @@ -586,6 +590,7 @@ class CTxMemPool
void removeProTxPubKeyConflicts(const CTransaction &tx, const CBLSPublicKey &pubKey);
void removeProTxCollateralConflicts(const CTransaction &tx, const COutPoint &collateralOutpoint);
void removeProTxSpentCollateralConflicts(const CTransaction &tx);
void removeProTxKeyChangedConflicts(const CTransaction &tx, const uint256& proTxHash, const uint256& newKeyHash);
void removeProTxConflicts(const CTransaction &tx);
void removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight);

Expand Down

0 comments on commit 5830353

Please sign in to comment.