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());
|
mapProTxRefs.emplace(proTx.proTxHash, tx.GetHash());
|
||||||
mapProTxBlsPubKeyHashes.emplace(proTx.pubKeyOperator.GetHash(), 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) {
|
} else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_REVOKE) {
|
||||||
CProUpRevTx proTx;
|
CProUpRevTx proTx;
|
||||||
if (!GetTxPayload(tx, proTx)) {
|
if (!GetTxPayload(tx, proTx)) {
|
||||||
@ -479,6 +486,12 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
mapProTxRefs.emplace(proTx.proTxHash, tx.GetHash());
|
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;
|
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)
|
void CTxMemPool::removeProTxConflicts(const CTransaction &tx)
|
||||||
{
|
{
|
||||||
removeProTxSpentCollateralConflicts(tx);
|
removeProTxSpentCollateralConflicts(tx);
|
||||||
@ -936,6 +967,15 @@ void CTxMemPool::removeProTxConflicts(const CTransaction &tx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
removeProTxPubKeyConflicts(tx, proTx.pubKeyOperator);
|
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 {
|
bool CTxMemPool::existsProviderTxConflict(const CTransaction &tx) const {
|
||||||
LOCK(cs);
|
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) {
|
if (tx.nType == TRANSACTION_PROVIDER_REGISTER) {
|
||||||
CProRegTx proTx;
|
CProRegTx proTx;
|
||||||
if (!GetTxPayload(tx, 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());
|
LogPrintf("%s: ERROR: Invalid transaction payload, tx: %s", __func__, tx.ToString());
|
||||||
return true; // i.e. can't decode payload == conflict
|
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());
|
auto it = mapProTxBlsPubKeyHashes.find(proTx.pubKeyOperator.GetHash());
|
||||||
return it != mapProTxBlsPubKeyHashes.end() && it->second != proTx.proTxHash;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -162,6 +162,10 @@ public:
|
|||||||
unsigned int GetSigOpCountWithAncestors() const { return nSigOpCountWithAncestors; }
|
unsigned int GetSigOpCountWithAncestors() const { return nSigOpCountWithAncestors; }
|
||||||
|
|
||||||
mutable size_t vTxHashesIdx; //!< Index in mempool's vTxHashes
|
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.
|
// 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 removeProTxPubKeyConflicts(const CTransaction &tx, const CBLSPublicKey &pubKey);
|
||||||
void removeProTxCollateralConflicts(const CTransaction &tx, const COutPoint &collateralOutpoint);
|
void removeProTxCollateralConflicts(const CTransaction &tx, const COutPoint &collateralOutpoint);
|
||||||
void removeProTxSpentCollateralConflicts(const CTransaction &tx);
|
void removeProTxSpentCollateralConflicts(const CTransaction &tx);
|
||||||
|
void removeProTxKeyChangedConflicts(const CTransaction &tx, const uint256& proTxHash, const uint256& newKeyHash);
|
||||||
void removeProTxConflicts(const CTransaction &tx);
|
void removeProTxConflicts(const CTransaction &tx);
|
||||||
void removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight);
|
void removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user