Track operator key changes in mempool and handle conflicts (#2540)
* 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
This commit is contained in:
parent
88f7bf0d82
commit
5830353373
@ -472,6 +472,13 @@ 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)) {
|
||||
@ -479,6 +486,12 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
|
||||
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;
|
||||
@ -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);
|
||||
@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)) {
|
||||
@ -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;
|
||||
}
|
||||
|
@ -162,6 +162,10 @@ public:
|
||||
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.
|
||||
@ -586,6 +590,7 @@ public:
|
||||
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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user