fix: update masternode rate limit on failed AddTrigger path - #65
Draft
PastaPastaPasta wants to merge 4 commits into
Draft
fix: update masternode rate limit on failed AddTrigger path#65PastaPastaPasta wants to merge 4 commits into
PastaPastaPasta wants to merge 4 commits into
Conversation
Add a unit test that floods CGovernanceManager with signature-valid but unparseable TRIGGER objects from a single operator key. Pre-fix every object lands in mapObjects; post-fix the rate limiter engages.
MasternodeRateUpdate was only called after a successful AddTrigger, so unparseable triggers never advanced mapLastMasternodeObject. Move the update before the early return so one operator key cannot flood mapObjects without limit (U009/U003).
Moving MasternodeRateUpdate() above the AddTrigger check (U009/U003) also moved the setAdditionalRelayObjects bookkeeping that lived inside it onto the failed-trigger path. A trigger created within RELIABLE_PROPAGATION_TIME of the future-deviation limit was therefore queued for deferred re-announcement even after AddTrigger failed and PrepareDeletion() marked it for removal -- so one signature-valid unparseable trigger would be announced to every peer by CheckPostponedObjects, and served to them on GETDATA (SerializeObjectForHash does not filter deleted objects), partly restoring the amplification the fix was meant to close. Split the relay scheduling into ScheduleAdditionalRelay() and call it only after the AddTrigger check, so rate accounting counts every attempt while only objects we keep are announced. Add a regression test for the relay path.
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
The V0NN/U0NN labels were private working identifiers from a local review pass. They carry no meaning outside that pass, so they are removed while the surrounding technical rationale is kept.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Audit finding U009 (high, CONFIRMED — downgraded from critical), plus U003, the same defect reported from a second audit region.
Issue
CGovernanceManager::AddGovernanceObjectInternalcalledMasternodeRateUpdateonly after theAddTriggercheck. The failed-trigger path returned early, so the rate buffer was never advanced.MasternodeRateCheckshort-circuitsreturn truewhenmapLastMasternodeObjecthas no entry for the outpoint, andMasternodeRateUpdateis the sole writer of that map. A masternode operator key submitting only unparseable triggers therefore stayed absent from the map forever and was never throttled — one key could floodmapObjectswithout limit.Fix
src/governance/governance.cpp: callMasternodeRateUpdatebefore theAddTriggercheck, so every attempt counts against the per-masternode buffer.The review follow-up fixes a problem introduced by that hoist.
MasternodeRateUpdatedid two unrelated things — advance the rate buffer, and insert intosetAdditionalRelayObjectsfor triggers created close toMAX_TIME_FUTURE_DEVIATION. Moving it above the check therefore armed deferred re-announcement for objects the node had just undone andPrepareDeletion-ed. SinceCheckPostponedObjectsonly inspectsfValid/fReadyand never the delete flag, those objects would be announced to every peer and served on GETDATA — restoring the fan-out amplification the fix exists to remove.The relay scheduling is now a separate
ScheduleAdditionalRelay()called only after the check passes. Rate accounting counts every attempt; only kept objects are announced.Tests
test: failed-trigger path must advance masternode rate limitprecedes the fix. Verified by reverting: without the fix 12/12 flooded objects are accepted, with it 6.Review notes
Wrongful-lockout was checked explicitly, since rate-limit bugs cut both ways. An honest MN creates one trigger per superblock cycle via
CreateGovernanceTrigger, and only if it is the projected payee — and it pre-checksMasternodeRateCheckand declines rather than burning buffer slots. WithRATE_BUFFER_SIZE = 5the buffer must span a very short window to trip, so honest cadence is nowhere near it.mapLastMasternodeObjectis persisted and keyed on the collateral outpoint, so a reconnect does not reset it.Known-remaining, deliberately out of scope:
GetRate()returns 0.0 below 5 samples, so a bounded 5-object burst per MN is still free; and TRIGGERvchDatahas no size cap (MAX_DATA_SIZEis enforced only for PROPOSALs). The latter likely matters more than the count limit.Based on
dashpay/dashdevelop @6d04c60ef36. Not rebase-tested against a newer tip; full functional suite not run.🤖 Generated with Claude Code