Skip to content

cardano-testnet | Refactor EpochStateView to use TVar instead of IORef#6538

Merged
carbolymer merged 1 commit intomasterfrom
mgalazyn/refactor/remove-epoch-state-polling
Apr 24, 2026
Merged

cardano-testnet | Refactor EpochStateView to use TVar instead of IORef#6538
carbolymer merged 1 commit intomasterfrom
mgalazyn/refactor/remove-epoch-state-polling

Conversation

@carbolymer
Copy link
Copy Markdown
Contributor

Checklist

  • Commit sequence broadly makes sense and commits have useful messages
  • New tests are added if needed and existing tests are updated. These may include:
    • golden tests
    • property tests
    • roundtrip tests
    • integration tests
      See Running tests for more details
  • Any changes are noted in the CHANGELOG.md for affected package
  • The version bounds in .cabal files are updated
  • CI passes. See note on CI. The following CI checks are required:
    • Code is linted with hlint. See .github/workflows/check-hlint.yml to get the hlint version
    • Code is formatted with stylish-haskell. See .github/workflows/stylish-haskell.yml to get the stylish-haskell version
    • Code builds on Linux, MacOS and Windows for ghc-9.6 and ghc-9.12
  • Self-reviewed the diff

Note on CI

If your PR is from a fork, the necessary CI jobs won't trigger automatically for security reasons.
You will need to get someone with write privileges. Please contact IOG node developers to do this
for you.

@carbolymer carbolymer requested a review from a team as a code owner April 16, 2026 15:28
@carbolymer carbolymer force-pushed the mgalazyn/refactor/remove-epoch-state-polling branch 3 times, most recently from 1d2609d to 0b7d0eb Compare April 16, 2026 19:18
Copy link
Copy Markdown
Contributor

@palas palas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, we don't have to worry about the polling interval anymore 👍

Comment thread cardano-testnet/src/Testnet/Components/Query.hs Outdated
Comment on lines +316 to +323
state <- readTVar epochStateView
case state of
Right _ -> pure state
Left (EpochStateFoldError _) -> pure state
Left EpochStateNotInitialised -> do
timedOut <- readTVar timedOutVar
guard timedOut
pure state
Copy link
Copy Markdown
Contributor

@palas palas Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
state <- readTVar epochStateView
case state of
Right _ -> pure state
Left (EpochStateFoldError _) -> pure state
Left EpochStateNotInitialised -> do
timedOut <- readTVar timedOutVar
guard timedOut
pure state
state <- readTVar epochStateView
timedOut <- readTVar timedOutVar
guard (state /= Left LeftEpochStateNotInitialised || timedOut)
pure state

I am just showing off

Copy link
Copy Markdown
Contributor Author

@carbolymer carbolymer Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice! We'd need some new Eq instances for that, but we'd have to write them manually for some ledger types.

@carbolymer carbolymer force-pushed the mgalazyn/refactor/remove-epoch-state-polling branch from 0b7d0eb to f872c06 Compare April 17, 2026 08:06
@carbolymer carbolymer requested a review from Copilot April 17, 2026 08:06
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Refactors cardano-testnet’s EpochStateView to use STM (TVar) so testnet wait/retry helpers can block on state updates instead of polling, improving responsiveness and reducing unnecessary wakeups.

Changes:

  • Replaced EpochStateView’s IORef storage with TVar and introduced a monotonic version counter for update notification.
  • Updated retry logic to await epoch-state updates (STM) rather than threadDelay polling.
  • Added changelog fragments documenting the refactor; normalized JSON fixture formatting (newline at EOF).

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 3 comments.

File Description
cardano-testnet/src/Testnet/Components/Query.hs Switches epoch state storage to STM and adds STM-based update waiting used by retry loops.
cardano-testnet/test/cardano-testnet-test/files/calculatePlutusScriptCost.json Formatting-only change (newline/EOF normalization).
cardano-testnet/changelog.d/20260416_160000_mgalazyn_stm_epoch_state_view.md Documents the STM refactor and change-notification approach.
cardano-testnet/changelog.d/20260416_124922_mgalazyn_refactor_retry_functions.md Updates changelog wording to match the refactor history.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread cardano-testnet/src/Testnet/Components/Query.hs Outdated
Comment on lines +260 to +269
awaitStateUpdateTimeout timeout EpochStateView{epochStateVersion, epochStateView} = liftIO $ do
version <- readTVarIO epochStateVersion
timedOutVar <- registerDelay . round $ timeout * 1_000_000
atomically $ do
v <- readTVar epochStateVersion
timedOut <- readTVar timedOutVar
case (v /= version, timedOut) of
(True, _) -> Just <$> readTVar epochStateView
(_, True) -> pure Nothing
_ -> STM.retry
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Flagging this as investigated but not acted on, with reasoning:

Mechanism: registerDelay doesn't spawn a thread per call.
It registers an entry in GHC's IO-manager timer queue (one long-lived manager per capability), so the accumulating cost is a priority-queue entry plus a TVar Bool per pending timeout, not a forked thread.

Scale: in steady-state retry loops (awaitStateUpdate fires roughly once per epoch; fallback is 300s), we'd have tens of pending entries at any time, low KB of memory.
Negligible at testnet-test scale.

Load-bearing: the 300s fallback here isn't redundant with retryUntilRightM's outer deadline.
That outer deadline is computed from getCurrentEpochNo/getSlotNumber/getBlockNumber, which read the same EpochStateView TVar that the fallback guards.
If the background fold thread hangs, the outer deadline stops advancing and the retry loop would block forever without this inner timeout.

Cancellable alternative: wrapping atomically in System.Timeout.timeout would cancel the timer on early return, but adds forkIO/killThread per call.
Trading one small overhead for another without a clear win.

Addressed the fast-path timer in getEpochStateDetails (line 323 comment) since that one accumulates without bound.

Comment thread cardano-testnet/src/Testnet/Components/Query.hs Outdated
@carbolymer carbolymer force-pushed the mgalazyn/refactor/remove-epoch-state-polling branch from f872c06 to e839e00 Compare April 17, 2026 08:17
@carbolymer carbolymer requested review from a team as code owners April 17, 2026 08:17
@carbolymer carbolymer force-pushed the mgalazyn/refactor/remove-watch-epoch-state-update branch from 6bd49c2 to 82f0f20 Compare April 17, 2026 10:44
@carbolymer carbolymer self-assigned this Apr 20, 2026
@carbolymer carbolymer force-pushed the mgalazyn/refactor/remove-watch-epoch-state-update branch from 82f0f20 to 75aece7 Compare April 21, 2026 07:47
@carbolymer carbolymer force-pushed the mgalazyn/refactor/remove-epoch-state-polling branch 2 times, most recently from d9ddb0e to 2a7327a Compare April 21, 2026 09:27
@carbolymer carbolymer requested review from Copilot and palas April 21, 2026 09:27
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Refactors EpochStateView in cardano-testnet to use STM (TVar) and introduces an STM-based change-notification mechanism so retry loops can block on state updates rather than polling.

Changes:

  • Replaced IORef-backed EpochStateView with TVar plus a monotonic version counter, and updated the background fold thread to write via STM.
  • Updated retry logic (retryUntilRightM) and epoch-state getters to block via STM (awaitStateUpdate) instead of threadDelay polling.
  • Added changelog entries and normalized a JSON test fixture (likely newline/formatting).

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 2 comments.

File Description
cardano-testnet/src/Testnet/Components/Query.hs Core refactor: EpochStateView now uses TVar + version counter; retry loops block on STM updates.
cardano-testnet/changelog.d/20260416_160000_mgalazyn_stm_epoch_state_view.md Documents the STM-based EpochStateView refactor and version counter rationale.
cardano-testnet/changelog.d/20260416_124922_mgalazyn_refactor_retry_functions.md Adjusts changelog wording to reflect the new EpochStateView shape.
cardano-testnet/test/cardano-testnet-test/files/calculatePlutusScriptCost.json Formatting-only tweak (appears to fix final newline/line accounting).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread cardano-testnet/src/Testnet/Components/Query.hs
Comment thread cardano-testnet/src/Testnet/Components/Query.hs Outdated
@carbolymer carbolymer force-pushed the mgalazyn/refactor/remove-epoch-state-polling branch 2 times, most recently from cdf2031 to 35413fc Compare April 21, 2026 13:42
@carbolymer carbolymer requested a review from Copilot April 21, 2026 13:43
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors cardano-testnet’s EpochStateView to use STM (TVar) instead of IORef, enabling retry loops to block on state changes rather than polling, and updates documentation/changelog artifacts accordingly.

Changes:

  • Replaced IORef-backed EpochStateView with TVar plus a monotonic version counter for STM-based change notification.
  • Updated retryUntilRightM to wait via STM (awaitStateUpdateTimeout) instead of threadDelay polling.
  • Updated changelog entries and a JSON test fixture formatting/newline.

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 2 comments.

File Description
cardano-testnet/src/Testnet/Components/Query.hs Refactors EpochStateView to TVar, adds versioning + STM wait helpers, and updates retry behavior to block on state updates.
cardano-testnet/test/cardano-testnet-test/files/calculatePlutusScriptCost.json Minor formatting/newline adjustment in a test fixture.
cardano-testnet/changelog.d/20260416_160000_mgalazyn_stm_epoch_state_view.md Documents the STM-based EpochStateView refactor and new notification mechanism.
cardano-testnet/changelog.d/20260416_124922_mgalazyn_refactor_retry_functions.md Updates a prior changelog entry to reflect the finalized EpochStateView field removal wording.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread cardano-testnet/src/Testnet/Components/Query.hs
Comment thread cardano-testnet/src/Testnet/Components/Query.hs Outdated
@carbolymer carbolymer force-pushed the mgalazyn/refactor/remove-epoch-state-polling branch from 35413fc to 7db627e Compare April 21, 2026 16:25
@carbolymer carbolymer requested a review from Copilot April 21, 2026 16:26
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors cardano-testnet’s EpochStateView to use STM primitives (TVar) rather than IORef, enabling retry/wait loops to block on state changes instead of polling with threadDelay.

Changes:

  • Replaced EpochStateView’s underlying mutable storage from IORef to TVar, and added a monotonic epochStateVersion TVar.
  • Updated retryUntilRightM to await STM-based state updates (with a fallback timeout) instead of polling.
  • Added/updated changelog entries documenting the maintenance refactor.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
cardano-testnet/src/Testnet/Components/Query.hs Migrates epoch-state tracking to STM (TVar) with a version counter and STM-based wakeups in retry loops.
cardano-testnet/changelog.d/20260416_160000_mgalazyn_stm_epoch_state_view.md Documents the STM refactor and the new change-notification mechanism.
cardano-testnet/changelog.d/20260416_124922_mgalazyn_refactor_retry_functions.md Updates prior changelog entry to reflect removal of unused EpochStateView fields.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread cardano-testnet/src/Testnet/Components/Query.hs
Comment thread cardano-testnet/src/Testnet/Components/Query.hs
@carbolymer carbolymer force-pushed the mgalazyn/refactor/remove-epoch-state-polling branch 3 times, most recently from 010681d to 4499504 Compare April 21, 2026 16:51
Copy link
Copy Markdown
Contributor

@palas palas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good 👍

@carbolymer carbolymer force-pushed the mgalazyn/refactor/remove-watch-epoch-state-update branch from 75aece7 to 47aa730 Compare April 22, 2026 12:06
Copy link
Copy Markdown
Contributor

@Jimbo4350 Jimbo4350 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just two comments to address. I am opening a PR to document this a bit more as the complexity increases with using STM.

Comment thread cardano-testnet/src/Testnet/Components/Query.hs Outdated
-> AnyNewEpochState
-> Maybe EpochNo
maybeExtractGovernanceActionExpiry txid (AnyNewEpochState sbe newEpochState _) =
caseShelleyToBabbageOrConwayEraOnwards
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove the use of caseShelleyToBabbageOrConwayEraOnwards?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will make a follow-up PR

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@carbolymer carbolymer force-pushed the mgalazyn/refactor/remove-watch-epoch-state-update branch from 47aa730 to 344c313 Compare April 24, 2026 06:57
@carbolymer carbolymer force-pushed the mgalazyn/refactor/remove-epoch-state-polling branch 2 times, most recently from 7bcedd3 to 5cbd71a Compare April 24, 2026 07:15
@carbolymer carbolymer force-pushed the mgalazyn/refactor/remove-epoch-state-polling branch from 5cbd71a to a205cac Compare April 24, 2026 07:52
Base automatically changed from mgalazyn/refactor/remove-watch-epoch-state-update to master April 24, 2026 08:16
@carbolymer carbolymer merged commit 50ffe15 into master Apr 24, 2026
29 of 31 checks passed
@carbolymer carbolymer deleted the mgalazyn/refactor/remove-epoch-state-polling branch April 24, 2026 09:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants