Skip to content

add Epoch.start_block_height legacy data-plane bridge (ENGN-9039) - #972

Open
zale144 wants to merge 3 commits into
alek/engn-8911-wire-startnewepoch-periodic-newepochhandlerfrom
alek/engn-9039-epoch-identity-bridge-noncev2-legacy-blockheight-data-plane
Open

add Epoch.start_block_height legacy data-plane bridge (ENGN-9039)#972
zale144 wants to merge 3 commits into
alek/engn-8911-wire-startnewepoch-periodic-newepochhandlerfrom
alek/engn-9039-epoch-identity-bridge-noncev2-legacy-blockheight-data-plane

Conversation

@zale144

@zale144 zale144 commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add Epoch.start_block_height set at StartNewEpoch from ctx.BlockHeight().
  • Expose Epoch.LegacyNonce() as the sole mapping into height-keyed submission/inference/reward APIs (no NonceV2.Payload() coercion).
  • Unit tests cover recording and the helper; canonical id remains NonceV2.

Notes

  • Epochs are not yet in genesis export/import; when epoch store genesis is added, include start_block_height.
  • Unblocks ENGN-8912 side-effect wiring during the parallel EndBlocker period; full cutover remains ENGN-8913.

Test plan

  • go test ./x/emissions/types/ -run 'TestEpochLegacyNonce|TestTopicExtraLag|TestNewEpochAppliesExtraLag'
  • go test ./x/emissions/keeper/ -run 'TestKeeperTestSuite/TestStartNewEpoch|TestKeeperTestSuite/TestActivateTopicStartsEpoch|TestKeeperTestSuite/TestInactivateTopicCancels'
  • CI green on this PR

Stacked on: #971 (ENGN-8911)
Linear: ENGN-9039

Made with Cursor


Summary by cubic

Bridges NonceV2 epochs to the legacy height-keyed data plane. StartNewEpoch now records Epoch.start_block_height from ctx.BlockHeight(), and Epoch.LegacyNonce() returns types.Nonce{BlockHeight} so FSM side effects can call height-keyed submission/inference/reward APIs without coercing NonceV2.Payload(). NonceV2 remains the canonical epoch id.

  • Proto: new start_block_height field on emissions.v10.Epoch only.
  • Keeper: sets the field in StartNewEpoch; LegacyNonce() is the sole bridge into height-keyed APIs.
  • Tests: cover recorded height, helper mapping, and non-coercion of NonceV2.Payload().
  • Linear ENGN-9039: unblocks ENGN-8912 side-effect wiring.
  • Migration: none now; include start_block_height when epochs enter genesis export/import.

Written for commit 4d87dfd. Summary will update on new commits.

Review in cubic

Record the block height at StartNewEpoch and expose LegacyNonce so
FSM side effects can call height-keyed APIs without coercing NonceV2.

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions

github-actions Bot commented Jul 31, 2026

Copy link
Copy Markdown

The latest Buf updates on your PR. Results from workflow Buf Linter / buf (pull_request).

BuildFormatLintBreakingUpdated (UTC)
✅ passed✅ passed✅ passed⏩ skippedAug 26, 2026, 1:47 PM

@cubic-dev-ai cubic-dev-ai Bot left a comment

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.

cubic analysis

1 issue found across 7 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="x/emissions/proto/emissions/v10/epoch.proto">

<violation number="1" location="x/emissions/proto/emissions/v10/epoch.proto:35">
P2: Epochs lacking the bridge field and epochs intentionally created at height 0 both deserialize as `0`, so consumers cannot distinguish missing legacy mapping from a valid zero-height mapping. According to linked Linear issue ENGN-9039, make this an `optional int64` to preserve that required presence distinction.</violation>
</file>

Linked issue analysis

Linked issue: ENGN-9039: Epoch identity bridge: NonceV2 ↔ legacy BlockHeight data plane

Status Acceptance criteria Notes
Proto: add int64 start_block_height on emissions.v10.Epoch The proto was updated to include start_block_height = 7 and generated Go files include the field and accessors.
Set the field in StartNewEpoch from ctx.BlockHeight() so every new Epoch records its start_block_height StartNewEpoch assigns sdkCtx.BlockHeight() to epoch.StartBlockHeight and tests assert the recorded value matches ctx.BlockHeight().
Provide Epoch.LegacyNonce() that maps to types.Nonce{BlockHeight: start_block_height} A LegacyNonce() method was added returning Nonce{BlockHeight: e.StartBlockHeight} and unit tests verify its behavior.
Unit tests cover recording of start_block_height and the LegacyNonce helper New/updated tests assert start_block_height is recorded and LegacyNonce returns the expected height; CI still pending but local tests listed in PR passed.
Ensure the canonical epoch id remains NonceV2 (do not coerce NonceV2.Payload() to height) PR preserves NonceV2 as the canonical id and includes a test asserting the epoch's Nonce.Payload() is not equal to the start height.
Document the decision and link this ticket from ENGN-8912 / ENGN-8913 as acceptance requires PR description references the related tickets and the intended unblock, but there's no evidence in the diff that the decision was documented on the issue tracker or that ENGN-8912/ENGN-8913 were updated/linked as required by the acceptance criteria.
Architecture diagram
sequenceDiagram
    participant EndBlocker as EndBlocker
    participant Keeper as emissions Keeper
    participant EpochStore as Epoch Store
    participant LegacyStore as Legacy BlockHeight-Keyed Store
    participant EpochType as Epoch Type
    participant API as Legacy height-keyed APIs

    Note over EndBlocker,API: NEW: Epoch.start_block_height bridge flow

    EndBlocker->>Keeper: StartNewEpoch(topicID)
    Keeper->>Keeper: Get topic from store
    Keeper->>EpochType: NewEpoch(nonce, topic, blockTime)
    Keeper->>Keeper: Set epoch.TopicId = topicID
    Keeper->>Keeper: CHANGED: Set epoch.StartBlockHeight = ctx.BlockHeight()
    Keeper->>EpochType: Init(&epoch) (FSM init)
    Keeper->>EpochStore: Set(epoch.Key(), epoch)
    
    Note over EpochType: LegacyNonce() helper
    
    API->>EpochType: GetEpoch(topicId, nonce)
    EpochStore-->>API: epoch object
    
    alt API needs BlockHeight key
        API->>EpochType: NEW: epoch.LegacyNonce()
        EpochType-->>API: Nonce{BlockHeight: epoch.StartBlockHeight}
        API->>LegacyStore: query with BlockHeight
        LegacyStore-->>API: legacy data
    else API uses canonical NonceV2
        API->>EpochType: epoch.Nonce (NonceV2)
        EpochType-->>API: canonical nonce
    end

    Note over Keeper,API: Canonical id remains NonceV2, not start_height payload
Loading

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

// Block height at StartNewEpoch. Transitional key into the legacy
// BlockHeight-keyed submission/inference/reward data plane (LegacyNonce).
// Canonical epoch id remains nonce (NonceV2).
int64 start_block_height = 7;

@cubic-dev-ai cubic-dev-ai Bot Jul 31, 2026

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.

P2: Epochs lacking the bridge field and epochs intentionally created at height 0 both deserialize as 0, so consumers cannot distinguish missing legacy mapping from a valid zero-height mapping. According to linked Linear issue ENGN-9039, make this an optional int64 to preserve that required presence distinction.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At x/emissions/proto/emissions/v10/epoch.proto, line 35:

<comment>Epochs lacking the bridge field and epochs intentionally created at height 0 both deserialize as `0`, so consumers cannot distinguish missing legacy mapping from a valid zero-height mapping. According to linked Linear issue ENGN-9039, make this an `optional int64` to preserve that required presence distinction.</comment>

<file context>
@@ -28,6 +28,11 @@ message Epoch {
+  // Block height at StartNewEpoch. Transitional key into the legacy
+  // BlockHeight-keyed submission/inference/reward data plane (LegacyNonce).
+  // Canonical epoch id remains nonce (NonceV2).
+  int64 start_block_height = 7;
 }
 
</file context>
Fix with cubic

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.

1 participant