# minPoolCost Audit — Findings **Run:** 2026-08-29 19:25 UTC **Source:** local `cexplorer` db-sync, version `13.6.0.5`, mainnet **Sync tip:** epoch **652**, block **13,872,736**, block time **2026-08-29 19:24:56 UTC** (tip was ~1 minute behind wall clock at query time — effectively live) **Last completed epoch:** 651. Epoch 652 is in progress and ends **2026-09-01 21:45:10 UTC**. SQL is in `sql/`, one file per number, each runnable standalone. Raw output is in `out_01.txt` … `out_06.txt`. --- ## READ FIRST — three results that cut against the brief's framing ### A. The "~300 ADA per block" figure is not stale. It is still correct. The brief treats ~300 ADA as an epoch-415 number quoted out of date. Recomputed from live chain data for the ten most recent completed reward epochs (641–650): **mean 298.11 ADA per block**, range 293.36–300.79, standard deviation 2.20. The circulating figure is accurate to within 0.6%. The "their numbers are from 2023 and nobody rechecked them" line does not survive contact with the data — at least not for this number. Numbers 1 and 3 also came back exactly as the brief predicted. What *is* true is that the figure is stable rather than stale. That is a different claim and a weaker one rhetorically, but it is the one the data supports. ### B. Most active pools are not on the floor, and never have been. Only **504 of 2,675** active pools (18.8%) declare a fixed cost of exactly 170 ADA. **1,749 pools (65.4%)** declare exactly 340 ADA — the pre-2023 floor — and are unaffected by where the floor sits. Restricting to pools that actually minted a block in epochs 641–650, the at-floor share rises but stays a minority: **361 of 1,217 minting pools (29.7%)**, producing 22.5% of blocks. The brief already anticipates this ("the honest version of my claim only covers the ones at 170"). The size of the gap is the point: the direct beneficiary group is roughly a fifth of pools by count and a quarter of block production. I have not established *why* 1,749 pools sit at 340. It could be inertia from before epoch 445, or a deliberate choice. Nothing in db-sync distinguishes those, and I am not going to guess. ### C. The governance action is not a clean minPoolCost cut. Action `ab474223…0ba306` changes **five** parameters, not one: | Parameter | Current | Proposed | |---|---:|---:| | `min_pool_cost` | 170,000,000 | **75,000,000** | | `max_tx_ex_mem` | 16,500,000 | 17,500,000 | | `max_tx_ex_steps` | 10,000,000,000 | 10,000,000,000 *(unchanged)* | | `max_block_ex_mem` | 72,000,000 | **77,500,000** | | `max_block_ex_steps` | 20,000,000,000 | 20,000,000,000 *(unchanged)* | Supporting it publicly means supporting a ~7.6% increase in the Plutus per-block memory budget as well. That may be fine, but it is a separate technical change bundled into the same vote and it is not mentioned in the brief. It is also *why* an SPO threshold applies at all. minPoolCost alone is an economic-group parameter with no SPO vote. `maxBlockExUnits` is in the security-relevant group, which is what brings the 51% SPO threshold into force. (Group membership comes from the Conway specification — db-sync does not record it. See the caveat in number 6.) ### D. Related, on vote state: the action is currently short in all three chambers. DReps 63.6% vs 67% needed; SPOs 14–26% vs 51% needed; Constitutional Committee 4 of 9 yes, 6 needed. Detail and caveats in number 6. The SPO shortfall is large and is not a rounding-error question. --- ## 1. minPoolCost change history **Claim under test:** was 340, dropped to 170 at epoch 445 (Oct 2023), unchanged since. **Confirmed exactly.** | Effective from epoch | Previous | New | Epoch start (UTC) | | |---:|---:|---:|---|---| | 208 | — | 340 ADA | 2020-07-29 21:44:51 | initial value, Shelley launch | | 445 | 340 ADA | **170 ADA** | 2023-10-27 21:45:10 | change | Unchanged for **207 epochs ≈ 2.83 years**. **Epochs used:** all of them — `epoch_param` holds 445 rows covering epochs 208–652 with no gaps. **Assumptions:** none. `min_pool_cost` is stored per epoch; change points are a `LAG()` over `epoch_no`. There is no minPoolCost before epoch 208 (Byron had no stake pools). `sql/01_min_pool_cost_history.sql` --- ## 2. Current gross reward per block **Claim under test:** ~300 ADA. **Recomputed value: 298.11 ADA.** See finding A above. **Metric, as fixed in the SQL header and reused identically in number 3:** > sum of `reward.amount` for `type IN ('leader','member')` at `earned_epoch = E`, divided by the count of blocks minted by a registered pool in epoch E. member + leader is the whole pool reward pot as distributed. The leader component already contains fixed cost + margin + the operator's own stake share; the member component is what remains after cost and margin. Their sum is therefore the pool's gross take *before* fixed cost and margin are deducted, which is what the brief asks for. | Epoch | Start | Blocks | Pools minting | Gross rewards (ADA) | ADA/block | |---:|---|---:|---:|---:|---:| | 641 | 2026-07-03 | 21,478 | 969 | 6,405,255 | 298.22 | | 642 | 2026-07-08 | 21,455 | 943 | 6,395,797 | 298.10 | | 643 | 2026-07-13 | 21,224 | 972 | 6,383,873 | 300.79 | | 644 | 2026-07-18 | 20,817 | 903 | 6,257,068 | 300.57 | | 645 | 2026-07-23 | 21,103 | 904 | 6,311,585 | 299.08 | | 646 | 2026-07-28 | 20,888 | 931 | 6,242,533 | 298.86 | | 647 | 2026-08-02 | 21,353 | 943 | 6,369,347 | 298.29 | | 648 | 2026-08-07 | 20,988 | 932 | 6,258,040 | 298.17 | | 649 | 2026-08-12 | 21,238 | 928 | 6,278,598 | 295.63 | | 650 | 2026-08-17 | 21,443 | 945 | 6,290,523 | 293.36 | **Mean of the ten epoch values: 298.11 ADA.** Pooled (total rewards ÷ total blocks): 298.10 ADA. Min 293.36, max 300.79, sd 2.20. **Epochs used: 641–650**, not 642–651. **Assumption I had to make:** epoch 651 is chronologically complete but the ledger has not computed its rewards yet — they land at the 652→653 boundary. `reward` is populated through `earned_epoch = 650` and has zero block-reward rows for 651. "The last 10 completed epochs" therefore means the last 10 with reward data: 641–650. **Other definitional calls:** - `type = 'refund'` excluded (deposit refunds, not block rewards). `reserves`/`treasury` do not appear against a pool in this schema version — db-sync 13.6 routes those to `reward_rest`. - Block denominator = blocks whose `slot_leader.pool_hash_id IS NOT NULL`. In every epoch used this equals the total block count exactly, so the choice makes no difference here. - Rewards for epoch E are attributed to blocks minted in epoch E, which is how the ledger computes them. `sql/02_gross_reward_per_block.sql` --- ## 3. minPoolCost as a share of gross reward, by pool size Using 298.11 ADA/block from number 2, recomputed inline so this file cannot drift from number 2. | Blocks in epoch | Gross reward (ADA) | 170 ADA is | at 75 ADA (proposed) | |---:|---:|---:|---:| | 1 | 298.11 | **57.0%** | 25.2% | | 2 | 596.22 | **28.5%** | 12.6% | | 5 | 1,490.54 | **11.4%** | 5.0% | | 20 | 5,962.16 | **2.9%** | 1.3% | A ~20x spread between a 1-block and a 20-block pool. The inverse-scaling claim holds. **Epochs used:** 641–650, via number 2. **Assumption I had to make:** the brief does not define how a pool "minting N blocks" earns. I assumed N × (mean gross reward per block) — the expectation, not a guarantee. Actual per-block reward varies slightly with the pool's own stake and pledge, so this is a linear approximation. **Caveat that belongs next to the table (arithmetic, not advocacy):** the ledger caps the operator's fixed cost at the pool's actual reward pot for the epoch. A pool whose gross reward is below 170 ADA does not pay a 170 ADA fee — it takes the whole smaller pot and members receive nothing. So a share approaching 100% means "members get ~zero", not "the operator is owed more than the pool earned". **Context for the 1-block row:** total active stake is 21.42bn ADA across ~21,199 blocks/epoch, i.e. roughly **1,010,400 ADA of stake per block**. The median at-floor pool holds 762,550 ADA (number 4), so the median pool in the affected group expects *fewer than one block per epoch*. The 1-block row is not an edge case for that cohort. `sql/03_min_pool_cost_share_by_pool_size.sql` --- ## 4. Pools sitting on the floor **504 active pools** declare a fixed cost of exactly 170 ADA — 18.8% of active pools, holding 4.84bn ADA (22.6% of active stake). See finding B above for the comparison against the 340 ADA cohort. | Declared fixed cost | Pools | % pools | Stake (ADA) | % stake | |---|---:|---:|---:|---:| | exactly 340 (pre-2023 floor) | 1,749 | 65.4% | 14,479,606,016 | 67.6% | | **exactly 170 (at floor)** | **504** | **18.8%** | **4,844,251,447** | **22.6%** | | other, above floor | 422 | 15.8% | 2,094,793,911 | 9.8% | Restricted to pools that minted a block in 641–650: 361 at floor (29.7% of minting pools, 22.5% of blocks) vs 722 at 340 (59.3%, 67.3%). No pool declares below 170 — the floor binds as expected, which is a useful sanity check on the query. ### Stake distribution of the 504 at-floor pools | | ADA | |---|---:| | total | 4,844,251,447 | | min | 3 | | 25th pct | 126,266 | | **median** | **762,550** | | mean | 9,611,610 | | 75th pct | 3,993,901 | | 95th pct | 64,358,249 | | max | 83,924,628 | | Stake bucket | Pools | % | Stake (ADA) | |---|---:|---:|---:| | under 100k | 107 | 21.2% | 1,802,002 | | 100k – 500k | 111 | 22.0% | 27,646,692 | | 500k – 1M | 54 | 10.7% | 38,836,787 | | 1M – 5M | 115 | 22.8% | 266,851,984 | | 5M – 10M | 16 | 3.2% | 119,028,925 | | 10M – 30M | 36 | 7.1% | 663,479,257 | | 30M+ | 65 | 12.9% | 3,726,605,799 | The distribution is severely skewed: mean is 12.6x the median, and 65 pools (12.9%) hold 77% of the cohort's stake. **Any claim of the form "the average at-floor pool…" will be wrong.** Use the median, or use the buckets. **Epoch used:** 652 (current) for stake and for the retirement test; 641–650 for the block-production cut. **Assumptions I had to make** — the brief does not fully define "active", so I stated it in the SQL and used: 1. registered: has at least one `pool_update`; 2. not retired: no `pool_retire`, **or** the newest retire certificate predates the newest registration (a re-registration cancels a pending retirement), **or** its `retiring_epoch` is still in the future; 3. non-zero stake in epoch 652's stake distribution. "Latest `pool_update` per pool" is `DISTINCT ON (hash_id)` ordered by `registered_tx_id DESC, id DESC`, so the last certificate in the last transaction wins — which is what the ledger applies. Condition 3 matters: without it, 2,894 pools pass as "active", including several hundred dormant registrations. This file reads `pool_update` / `pool_retire` / `epoch_stake` only. It does not touch `tx_out`, so the consumed/prune-mode caveat in the brief does not apply to it. `sql/04_pools_at_floor.sql` --- ## 5. Active pool count over time **Window: epochs 433–651** (epoch 433 began 2023-08-28, three years before the run date; 651 is the last completed epoch). Full 219-epoch series is in `out_05.txt`. **"Active" is defined as:** distinct pools holding non-zero stake in `epoch_stake` for that epoch. Presence in `epoch_stake` already implies registered and not retired as at that snapshot, so the one condition captures all three properties in the brief's likely intent. A second series is reported alongside, because the two have not moved together and they answer different questions — the first counts pools that *exist*, the second counts pools that are *operating*. | | Epoch 433 (2023-08-28) | Epoch 651 (2026-08-22) | Change | |---|---:|---:|---:| | Active pools (non-zero stake) | 2,921 | 2,678 | **−243 (−8.3%)** | | Pools minting ≥1 block | 1,147 | 939 | **−208 (−18.1%)** | Annual snapshots: | Epoch | Date | Active pools | Minting | Total active stake (ADA) | |---:|---|---:|---:|---:| | 433 | 2023-08-28 | 2,921 | 1,147 | 22,739,705,233 | | 506 | 2024-08-27 | 2,868 | 1,075 | 22,600,232,614 | | 579 | 2025-08-27 | 2,757 | 1,012 | 21,898,391,707 | | 651 | 2026-08-22 | 2,678 | 939 | 21,567,679,743 | The decline is monotone year over year in both series, and steeper in the block-producing series (−18.1%) than in the registration series (−8.3%). **What this does and does not establish:** it is a real, consistent decline. It is *correlation with* the period in which the floor has been 170 ADA, not evidence that the floor caused it. Total active stake also fell 5.2% over the same window, and pool count responds to delegator concentration, the `k` parameter, and ADA price as well. I have not tried to separate those, and the data here cannot. Presenting this as "direct evidence of structural squeeze" would be a claim the query does not support. Uses canonical `epoch_stake` / `block` / `slot_leader`, not the local `pool_epoch_stake_cache` derived table. `sql/05_active_pool_count.sql` --- ## 6. Current vote state **Action:** `ab474223d40e2e3540555364be27e161a809c33651408f43d84acff10c0ba306` gov_action_proposal id **154**, type `ParameterChange`, proposed epoch **646** (2026-07-30 17:21:01 UTC), deposit 100,000 ADA. Status: **not ratified, not enacted, not expired, not dropped.** `expiration = 653`. ### The deadline in the brief is correct Past actions in this database are evaluated at the boundary *entering* the epoch recorded in `expiration`, and are either ratified or expired at that point (e.g. action 152: expiration 649, ratified_epoch 649; action 151: expiration 648, expired_epoch 648). For action 154 that boundary is the one entering epoch 653, i.e. **the end of epoch 652 = 2026-09-01 21:45:10 UTC**. Votes must be on-chain before then. This matches the brief's "voting closes 1 September 2026". ### Thresholds in force (epoch 652) `dvt_p_p_economic_group` 0.67 · `dvt_p_p_technical_group` 0.67 · `pvtpp_security_group` 0.51 · `committee_min_size` 5 · committee quorum 2/3. The brief's 67% / 51% are correct. See finding C for why an SPO threshold applies at all. ### The snapshot rule — established empirically, not assumed The brief asked me not to guess this. I did not; I derived it and tested it. **Rule:** at the boundary entering epoch N, voting power is `drep_distr` for `epoch_no = N`, and the votes counted are those on-chain up to and including epoch N−1. Tested against three past actions whose recorded outcomes are in this database: | Action | Recorded outcome | Snapshot N−1 | Snapshot N | Threshold | Match? | |---|---|---:|---:|---:|---| | 141 | ratified epoch 644 | 0.506 | 0.726 | 0.60 | ✅ flips at 644 | | 145 | ratified epoch 646 | 0.546 | 0.771 | 0.67 | ✅ flips at 646 | | 151 | expired epoch 648 | — | 0.024 | 0.67 | ✅ below | Both boundary cases flip at exactly the recorded ratification epoch, so the snapshot rule and the DRep formula below are jointly confirmed. **The limitation you need to know about:** the snapshot that will actually govern is `drep_distr` for epoch **653**, and it **does not exist yet** — the maximum `epoch_no` in `drep_distr` is 652. Every figure below uses the epoch-652 snapshot as a proxy. Section F of the SQL quantifies the movement: the DRep yes-ratio has sat in a 0.6359–0.6447 band across snapshots 649–652, so the proxy error is on the order of ±0.5 percentage points — well inside the current 3.4-point shortfall, but not zero. ### DReps — snapshot epoch 652, all votes on-chain to date | | ADA | |---|---:| | Yes | 3,178,984,829 | | No | 229,773,790 | | Abstain (explicit) | 106,400,987 | | Not voted | 1,440,000,389 | | AlwaysNoConfidence (counts as No) | 150,047,860 | | **Denominator** | **4,998,806,867** | | AlwaysAbstain (excluded) | 9,776,721,979 | | Inactive DReps (excluded) | 179,123,115 | **Yes ratio 63.59% vs 67.00% needed.** **Additional yes stake required: 170,215,772 ADA (~170.2M).** **Formula** (the one validated above): denominator = active registered DReps that did not vote Abstain, plus AlwaysNoConfidence. AlwaysAbstain is excluded entirely — it is abstention by definition. A DRep is active when `drep_distr.active_until >= snapshot epoch`; inactive DReps are excluded from both sides. Non-voting DReps stay in the denominator and count as No. Repeat votes are deduplicated, latest vote per voter wins (6 DReps and 1 SPO voted twice on this action). Worth knowing: **AlwaysAbstain holds 9.78bn ADA — about 65% of all DRep-delegated stake** — and is removed from the denominator. The effective electorate is ~5.0bn ADA, not ~15bn. ### SPOs — snapshot epoch 652 — READ THE CAVEAT **I could not validate the SPO rule to the standard I applied to DReps.** No action in this database discriminates between the candidate rules: the only action with an SPO threshold and a known ratification epoch (129, HardForkInitiation) was gated by the Constitutional Committee, not by the SPO tally, so it cannot separate them. Rather than pick one and present it as fact, both are given: **(a) non-voting pools count as No:** | Yes | No | Abstain | Not voted | Denominator | Ratio | |---:|---:|---:|---:|---:|---:| | 2,923,871,321 | 490,610,235 | 711,458,277 | 17,293,222,392 | 20,707,703,948 | **14.12%** | → additional yes stake required: **7,637,057,693 ADA (~7.64bn)** **(b) non-voting pools default from their reward account's vote delegation** (AlwaysAbstain → Abstain and out of the denominator; AlwaysNoConfidence or undelegated → No): | Yes | No | Abstain (incl. defaults) | Denominator | Ratio | |---:|---:|---:|---:|---:| | 2,923,871,321 | 8,171,476,369 | 10,323,814,535 | 11,095,347,690 | **26.35%** | → additional yes stake required: **2,734,756,001 ADA (~2.73bn)** 831 pools currently delegate their reward account to AlwaysAbstain, which is why the two variants differ so much. Variant (b) is what the Conway specification describes for the post-bootstrap era, but that is read from the specification, not derived from this database. **The qualitative answer is the same either way: 14–26% against a 51% threshold, a shortfall of 2.7–7.6bn ADA.** The uncertainty in the rule does not change the conclusion, only its magnitude. If you quote a single SPO number it will be challenged; quote the range. Two further SPO caveats: - SPO voting power is taken as the pool's stake in `epoch_stake` for the snapshot epoch. db-sync's `pool_stat.voting_power` would be the direct source, but **`pool_stat` is empty in this instance** and cannot be used. - The epoch-653 proxy limitation applies here too. ### Constitutional Committee — a gate the brief does not mention | Committee size | Quorum | Yes | No | Abstain | Not voted | Ratio | Needed | |---:|---|---:|---:|---:|---:|---:|---:| | 9 | 2/3 | 4 | 0 | 0 | 5 | 44.4% | 6 | **2 more CC yes votes are required.** Ratification needs all applicable chambers, so this binds independently of the DRep and SPO tallies. It is also precisely what stopped action 129 from ratifying an epoch earlier than it did, so it is not a theoretical concern. **A timing risk worth checking before you publish:** 6 of the 9 committee members have `expiration_epoch = 653` — the same boundary at which this action is decided. The remaining 3 expire at epoch 726. `committee_min_size` is 5. I have not established whether a member with `expiration_epoch = 653` is still eligible to vote *at* the boundary entering 653 or is already expired, and db-sync does not record the tie-break. There is also a pending `NewCommittee` action (id 155, proposed the same epoch, same expiration 653) which appears intended to refresh the committee. I flag this as an open question rather than assert an outcome — it could matter a great deal for whether this action can ratify at all. `sql/06_vote_state.sql` --- ## Summary of assumptions | # | Assumption | Why it was needed | |---|---|---| | 2 | Epochs 641–650, not 642–651 | Epoch 651's rewards are not computed until the 652→653 boundary; `reward` has no block-reward rows for 651 | | 2 | member + leader = gross pot | Brief's definition; leader already includes cost + margin | | 3 | Pool minting N blocks earns N × mean per-block reward | Brief does not define it; linear approximation of the expectation | | 4 | "Active" = registered + not retired + non-zero stake in epoch 652 | Brief says "likely intent"; without the stake condition the count is 2,894 rather than 2,675 | | 4 | Re-registration cancels a pending retirement | Matches ledger behaviour | | 5 | "Active" = non-zero stake in `epoch_stake` for that epoch | Single condition that captures registered + not retired + non-zero stake | | 6 | Snapshot = `drep_distr` at epoch N, votes through N−1 | **Not assumed — derived and validated against 3 past actions** | | 6 | Epoch-652 snapshot used as proxy for epoch 653 | The governing snapshot does not exist yet; sensitivity band is ±0.5pp | | 6 | SPO non-voter rule | **Could not be validated.** Both variants reported | | 6 | SPO voting power from `epoch_stake` | `pool_stat` is empty in this instance | | 6 | `maxBlockExUnits` is in the security-relevant group | From the Conway specification; not recorded in db-sync | ## Notes on the environment caveat in the brief The consumed/prune-mode issue (`tx_out.consumed_by_tx_id IS NULL` rather than `NOT EXISTS` against `tx_in`) did not arise: none of the six numbers require UTxO resolution. They read `epoch_param`, `reward`, `block`, `slot_leader`, `pool_update`, `pool_retire`, `epoch_stake`, `drep_distr`, `drep_hash`, `delegation_vote`, `voting_procedure`, `gov_action_proposal`, `param_proposal`, `committee*` and `epoch`. No query in `sql/` touches `tx_out` or `tx_in`. One related discovery: **`pool_stat` is empty** in this db-sync instance. Block counts and pool stake are therefore derived from `block`/`slot_leader` and `epoch_stake`, and `pool_stat.voting_power` is unavailable for number 6.