mirror of
https://github.com/Xahau/xahaud.git
synced 2026-04-29 15:37:46 +00:00
fix(export): deduplicate export sigs across proposals within a round
This commit is contained in:
@@ -313,6 +313,7 @@ RCLConsensus::Adaptor::propose(RCLCxPeerPos::Proposal const& proposal)
|
||||
//@@start export-sig-attachment
|
||||
// Attach export signatures for any ttEXPORT txns in the current set.
|
||||
// Each "signature" is: txnHash (32 bytes) + validator pubkey (33 bytes).
|
||||
// Only attach once per export per round (markSent deduplicates).
|
||||
// XAHAUD_NO_EXPORT_SIG=1 disables sig attachment (for testing sub-quorum).
|
||||
if (auto const* noSig = std::getenv("XAHAUD_NO_EXPORT_SIG");
|
||||
noSig && std::string(noSig) == "1")
|
||||
@@ -329,6 +330,11 @@ RCLConsensus::Adaptor::propose(RCLCxPeerPos::Proposal const& proposal)
|
||||
if (stx && stx->getTxnType() == ttEXPORT)
|
||||
{
|
||||
auto const txHash = stx->getTransactionID();
|
||||
|
||||
// Only attach our sig on the first proposal this round.
|
||||
if (!exportSigCollector().markSent(txHash))
|
||||
continue;
|
||||
|
||||
Serializer s;
|
||||
s.addBitString(txHash);
|
||||
s.addRaw(validatorKeys_.keys->publicKey.slice());
|
||||
@@ -1668,6 +1674,7 @@ RCLConsensus::Adaptor::validatorKey() const
|
||||
void
|
||||
RCLConsensus::Adaptor::clearRngState()
|
||||
{
|
||||
exportSigCollector().clearRound();
|
||||
pendingCommits_.clear();
|
||||
pendingReveals_.clear();
|
||||
nodeIdToKey_.clear();
|
||||
|
||||
@@ -8,13 +8,16 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/// Minimal export signature collector for the retriable export approach.
|
||||
/// Tracks which validators have "signed" each pending export.
|
||||
/// Export signature collector for the retriable export approach.
|
||||
/// Tracks which validators have "signed" each pending export, and
|
||||
/// which exports we've already attached our own sig to (so we don't
|
||||
/// redundantly re-send on every proposal).
|
||||
/// Thread-safe.
|
||||
class ExportSigCollector
|
||||
{
|
||||
mutable std::mutex mutex_;
|
||||
std::unordered_map<uint256, std::set<PublicKey>> sigs_;
|
||||
std::set<uint256> sentThisRound_;
|
||||
|
||||
public:
|
||||
void
|
||||
@@ -46,10 +49,26 @@ public:
|
||||
std::lock_guard lock(mutex_);
|
||||
sigs_.erase(txnHash);
|
||||
}
|
||||
|
||||
/// Returns true if we haven't sent our sig for this tx yet this round.
|
||||
/// Marks it as sent on first call.
|
||||
bool
|
||||
markSent(uint256 const& txnHash)
|
||||
{
|
||||
std::lock_guard lock(mutex_);
|
||||
return sentThisRound_.insert(txnHash).second;
|
||||
}
|
||||
|
||||
/// Clear per-round state. Call at the start of each consensus round.
|
||||
void
|
||||
clearRound()
|
||||
{
|
||||
std::lock_guard lock(mutex_);
|
||||
sentThisRound_.clear();
|
||||
}
|
||||
};
|
||||
|
||||
/// Global instance for the prototype.
|
||||
/// In production this would be owned by Application.
|
||||
/// Global instance. In production this would be owned by Application.
|
||||
inline ExportSigCollector&
|
||||
exportSigCollector()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user