From 860dee7e44ab1bae2bf46b53bc7212dec385e5d1 Mon Sep 17 00:00:00 2001 From: chiliec Date: Thu, 13 Aug 2026 01:32:47 +0300 Subject: [PATCH] fix(pm): couple closed-market retention to the commit reveal deadline (validate bound) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Defensive hardening for the commit-reveal escrow path. A commit's reveal deadline can fall up to (pm_batch_epoch_blocks + pm_reveal_window_blocks) blocks after the commit, and its escrow is only refunded/forfeited by the reveal-forfeit cron at that deadline. gc_market deletes pm_commit rows unconditionally once a market has been finalized for pm_closed_market_retention_sec, with no status-0 refund. Today this is safe purely by parameter magnitudes (5 d retention vs ~11 min worst-case reveal deadline). Nothing in code enforces the ordering, and pm_closed_market_retention_sec had no lower bound — a misconfigured median (retention below the reveal window) plus a sustained cron cap-starvation could let a still-unrevealed commit be garbage-collected before its escrow is returned, stranding a bettor's stake. Add a validate() assert requiring pm_closed_market_retention_sec > (pm_batch_epoch_blocks + pm_reveal_window_blocks) * CHAIN_BLOCK_INTERVAL so the "a commit is always cleared before its market is GC'd" invariant holds by construction. Both operands are already validated positive just above. Defaults satisfy it with wide margin (432000 > (20 + 200) * 3 = 660); no testnet override changes these. Header syntax-checks clean against the chain build flags. No behavioural change for any valid configuration. --- .../include/graphene/protocol/chain_operations.hpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/libraries/protocol/include/graphene/protocol/chain_operations.hpp b/libraries/protocol/include/graphene/protocol/chain_operations.hpp index 9e111e3d56..81e64fab45 100644 --- a/libraries/protocol/include/graphene/protocol/chain_operations.hpp +++ b/libraries/protocol/include/graphene/protocol/chain_operations.hpp @@ -742,6 +742,18 @@ namespace graphene { namespace protocol { FC_ASSERT(pm_commit_no_reveal_penalty_percent <= 10000, "pm_commit_no_reveal_penalty_percent out of range"); FC_ASSERT(pm_batch_epoch_blocks > 0, "pm_batch_epoch_blocks must be positive"); FC_ASSERT(pm_reveal_window_blocks > 0, "pm_reveal_window_blocks must be positive"); + // A commit's reveal deadline can fall up to (batch_epoch + reveal_window) blocks + // after the commit (pm_commit_bet), and its escrow is only refunded/forfeited by the + // reveal-forfeit cron at that deadline. gc_market deletes commit rows unconditionally + // once a market has been finalized for pm_closed_market_retention_sec. Require the + // retention to strictly exceed the worst-case reveal deadline so a still-unrevealed + // commit can never be garbage-collected before its escrow is returned — makes the + // "commit is always cleared before GC" invariant hold by construction, not by the + // default parameter magnitudes (5 d vs ~11 min) alone. + FC_ASSERT(pm_closed_market_retention_sec + > (uint64_t)(pm_batch_epoch_blocks + pm_reveal_window_blocks) * CHAIN_BLOCK_INTERVAL, + "pm_closed_market_retention_sec must exceed the worst-case commit reveal deadline " + "((pm_batch_epoch_blocks + pm_reveal_window_blocks) * CHAIN_BLOCK_INTERVAL)"); FC_ASSERT(pm_processing_cap_per_block > 0, "pm_processing_cap_per_block must be positive"); FC_ASSERT(pm_lazy_alloc_percent <= 10000, "pm_lazy_alloc_percent out of range"); FC_ASSERT(pm_lazy_max_total_alloc_percent <= 10000, "pm_lazy_max_total_alloc_percent out of range");