-
Notifications
You must be signed in to change notification settings - Fork 1.2k
fix: reconstruct ISLOCK locally when recsig arrived first #7291
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -384,10 +384,6 @@ void InstantSendSigner::TrySignInstantSendLock(const CTransaction& tx) | |
|
|
||
| auto id = islock.GetRequestId(); | ||
|
|
||
| if (m_sigman.HasRecoveredSigForId(llmqType, id)) { | ||
| return; | ||
| } | ||
|
|
||
| const auto& llmq_params_opt = Params().GetLLMQ(llmqType); | ||
| assert(llmq_params_opt); | ||
| const auto quorum = llmq::SelectQuorumForSigning(llmq_params_opt.value(), m_chainstate.m_chain, m_qman, id); | ||
|
|
@@ -402,6 +398,9 @@ void InstantSendSigner::TrySignInstantSendLock(const CTransaction& tx) | |
| quorum->m_quorum_base_block_index->nHeight % llmq_params_opt->dkgInterval; | ||
| islock.cycleHash = quorum->m_quorum_base_block_index->GetAncestor(cycle_height)->GetBlockHash(); | ||
|
|
||
| // Emplace into creatingInstantSendLocks first so that any concurrent recsig listener | ||
| // (firing on a parallel verification worker) finds the entry and handles reconstruction | ||
| // through HandleNewInstantSendLockRecoveredSig. | ||
| { | ||
| LOCK(cs_creating); | ||
| auto e = creatingInstantSendLocks.emplace(id, std::move(islock)); | ||
|
|
@@ -411,6 +410,33 @@ void InstantSendSigner::TrySignInstantSendLock(const CTransaction& tx) | |
| txToCreatingInstantSendLocks.emplace(tx.GetHash(), &e.first->second); | ||
| } | ||
|
|
||
| // After emplacing, check whether the recsig is already in db. If yes, the listener | ||
| // either already ran while creating was empty (so we must reconstruct here), or it | ||
| // ran after our emplace and already removed the entry (so the find below misses). | ||
| // Either case is handled correctly by the find/erase pattern. | ||
| if (llmq::CRecoveredSig recSig; m_sigman.GetRecoveredSigForId(llmqType, id, recSig)) { | ||
| InstantSendLockPtr islock_ptr; | ||
| { | ||
| LOCK(cs_creating); | ||
| auto it = creatingInstantSendLocks.find(id); | ||
| if (it == creatingInstantSendLocks.end()) { | ||
| // The listener already fired after our emplace and reconstructed; nothing to do. | ||
| return; | ||
| } | ||
| islock_ptr = std::make_shared<InstantSendLock>(std::move(it->second)); | ||
| txToCreatingInstantSendLocks.erase(islock_ptr->txid); | ||
| creatingInstantSendLocks.erase(it); | ||
| } | ||
| if (recSig.getMsgHash() != tx.GetHash()) { | ||
| LogPrintf("%s -- txid=%s: existing recovered islock sig has conflicting msgHash %s\n", | ||
| __func__, tx.GetHash().ToString(), recSig.getMsgHash().ToString()); | ||
| return; | ||
| } | ||
| islock_ptr->sig = recSig.sig; | ||
| m_isman.TryEmplacePendingLock(::SerializeHash(*islock_ptr), /*id=*/-1, islock_ptr); | ||
| return; | ||
| } | ||
|
|
||
| m_shareman.AsyncSignIfMember(llmqType, m_sigman, id, tx.GetHash(), quorum->m_quorum_base_block_index->GetBlockHash()); | ||
|
Comment on lines
401
to
440
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Suggestion: The race fix changed ISLOCK reconstruction without adding regression coverage for the reordered path This change only touches source: ['codex'] 🤖 Fix this with AI agents |
||
| } | ||
| } // namespace instantsend | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When
GetRecoveredSigForIdreturns true, this branch reuses thecycleHashcomputed earlier fromSelectQuorumForSigningat the current tip and only swaps inrecSig.sig. If the recovered signature was created in an older active set (for example, tx seen after a quorum rotation), the reconstructed ISLOCK can carry acycleHashthat doesn't matchrecSig's quorum, so peers that verify viacycleHash(seenet_instantsend.cppquorum selection path) may reject the relayed lock. This path should derive/validatecycleHashfromrecSig.getQuorumHash()before enqueuing.Useful? React with 👍 / 👎.