Skip to content

Conversation

@wolf31o2
Copy link
Member

@wolf31o2 wolf31o2 commented Nov 2, 2025

Summary

This PR replaces the hard-coded slot threshold for bulk blockfetch operations with the protocol-defined stability window, addressing the TODO comment in the codebase.

Changes

Core Changes

  • **Replaced hard-coded ** with dynamic calculation based on the stability window
  • Era-aware security parameter selection:
    • Byron era: Uses parameter from
    • Shelley+ eras: Uses from
  • Updated stability window calculation:
    • Byron era: stability window = (security parameter)
    • Shelley+ eras: stability window = (where f is active slots coefficient)

Files Modified

  • : Updated blockfetch slot threshold logic and epoch nonce calculation
  • : Updated block validation to use correct security parameters

Benefits

  1. Protocol Compliance: Now uses the proper Cardano protocol-defined security parameters
  2. Era Awareness: Correctly handles different security parameter sources across Byron and Shelley+ eras
  3. Network Flexibility: Automatically adapts to different network configurations (mainnet, testnet, etc.)
  4. Maintainability: Eliminates hard-coded values and TODO comments

Testing

  • Code compiles successfully
  • All existing tests pass
  • No breaking changes to existing functionality

Technical Details

The stability window is calculated differently based on the era:

  • Byron era (ID 0): Uses the parameter directly as the stability window
  • Shelley+ eras: Calculates where is the security parameter and is the active slots coefficient from genesis

This ensures that bulk blockfetch operations stop at the appropriate distance from the chain tip, as defined by the protocol's stability guarantees.

Summary by CodeRabbit

  • Bug Fixes

    • Era-aware stability thresholds are now applied when deciding block-body fetches, reducing premature catch-up exits and improving tip tracking; missing or invalid genesis/config now produce clearer, user-facing errors.
  • Refactor

    • Epoch-nonce and stability-window calculations made era-aware with validated parameters and safe fallbacks, improving accuracy and resilience across protocol eras.
  • Tests

    • Comprehensive unit tests added for stability-window and epoch-nonce behavior across eras and edge cases.

Closes #591

@wolf31o2 wolf31o2 requested a review from a team as a code owner November 2, 2025 18:30
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 2, 2025

📝 Walkthrough

Walkthrough

The PR makes ledger logic era-aware for stability-window and slot-threshold calculations. It adds blockfetchBatchSlotThresholdDefault, computes an era-specific slot threshold in handleEventChainsyncBlockHeader (Byron uses Byron genesis K; Shelley+ uses floor((3*K)/ActiveSlotsCoeff) with validations), and replaces static gating for block-body fetches. calculateEpochNonce and ledger processing now select era-specific genesis fields, validate presence/non-negativity of K/SecurityParam and ActiveSlotsCoeff, check for overflow in stability-window calculations, and return explicit errors for missing/invalid genesis. Adds LedgerState.calculateStabilityWindow() and extensive tests covering Byron/Shelley-era behavior.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Verify era detection and correct selection between Byron.K and Shelley.SecurityParam.
  • Validate stability-window formula (floor((3*K)/f)), integer rounding, big-int/overflow handling and conversion edges.
  • Inspect ActiveSlotsCoeff nil/zero checks and resulting error messages.
  • Confirm new error paths are propagated and handled by chainsync and ledger-processing loops.
  • Review added tests (ledger/chainsync_test.go, ledger/state_test.go) for correctness, completeness, and edge-case coverage.

Pre-merge checks and finishing touches

✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: replacing a hard-coded slot threshold with a dynamic stability window calculation, which aligns with the primary objective of the PR.
Linked Issues check ✅ Passed The PR successfully implements the core requirements from issue #591: replacing hard-coded slot threshold with protocol-derived stability window calculation, with era-aware security parameter selection.
Out of Scope Changes check ✅ Passed All changes are directly related to the linked issue: implementing era-aware stability window calculation for slot threshold determination, with supporting logic in chainsync and state management.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/use-stability-window-for-blockfetch

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ad2f39f and 4a59bd9.

📒 Files selected for processing (4)
  • ledger/chainsync.go (3 hunks)
  • ledger/chainsync_test.go (1 hunks)
  • ledger/state.go (2 hunks)
  • ledger/state_test.go (1 hunks)
🧰 Additional context used
🧠 Learnings (8)
📚 Learning: 2025-10-22T21:28:48.396Z
Learnt from: wolf31o2
Repo: blinklabs-io/dingo PR: 971
File: utxorpc/sync_test.go:339-339
Timestamp: 2025-10-22T21:28:48.396Z
Learning: In utxorpc/sync_test.go, tests must not pass database/models.Block into chain.Chain.AddBlock. They should call models.Block.Decode() and pass the resulting github.com/blinklabs-io/gouroboros/ledger/common.Block to AddBlock.

Applied to files:

  • ledger/chainsync_test.go
📚 Learning: 2025-10-22T21:29:26.924Z
Learnt from: wolf31o2
Repo: blinklabs-io/dingo PR: 971
File: ledger/state_test.go:248-248
Timestamp: 2025-10-22T21:29:26.924Z
Learning: For tests under ledger/, prefer constructing a minimal ledger Block (MockBlock mirroring chain/chain_test.go) and pass it to Chain.AddBlock, rather than using database/models.Block or relying on models.Block.Decode().

Applied to files:

  • ledger/chainsync_test.go
  • ledger/state_test.go
📚 Learning: 2025-10-22T20:19:25.277Z
Learnt from: wolf31o2
Repo: blinklabs-io/dingo PR: 971
File: ledger/state_test.go:434-434
Timestamp: 2025-10-22T20:19:25.277Z
Learning: In this repo’s tests, use models.Block.Decode() to obtain a ledger.Block before calling chain.Chain.AddBlock, since AddBlock expects a ledger.Block, while LedgerState.GetBlock returns a database/models.Block.

Applied to files:

  • ledger/chainsync_test.go
  • ledger/state_test.go
📚 Learning: 2025-10-22T20:13:35.164Z
Learnt from: wolf31o2
Repo: blinklabs-io/dingo PR: 971
File: ledger/state_test.go:56-56
Timestamp: 2025-10-22T20:13:35.164Z
Learning: In tests under ledger/state_test.go, PrimaryChain.AddBlock expects a "github.com/blinklabs-io/gouroboros/ledger/common".Block; use models.Block.Decode() to obtain that type before calling AddBlock.

Applied to files:

  • ledger/chainsync_test.go
  • ledger/state_test.go
📚 Learning: 2025-10-22T20:13:35.972Z
Learnt from: wolf31o2
Repo: blinklabs-io/dingo PR: 971
File: utxorpc/sync_test.go:339-339
Timestamp: 2025-10-22T20:13:35.972Z
Learning: Unit tests under utxorpc should assert that models.Block.Decode() returns a github.com/blinklabs-io/gouroboros/ledger/common.Block, not rely on models.Block directly in protocol/ledger-facing logic.

Applied to files:

  • ledger/chainsync_test.go
  • ledger/state_test.go
📚 Learning: 2025-10-22T20:19:26.360Z
Learnt from: wolf31o2
Repo: blinklabs-io/dingo PR: 971
File: utxorpc/sync_test.go:91-91
Timestamp: 2025-10-22T20:19:26.360Z
Learning: In utxorpc/sync_test.go, tests should not construct database/models.Block directly for sync server use. Instead, build a models.Block only as a container for CBOR and call models.Block.Decode() to obtain a github.com/blinklabs-io/gouroboros/ledger/common.Block (or the repository’s ledger.Block interface), and use that decoded value in the test.

Applied to files:

  • ledger/chainsync_test.go
  • ledger/state_test.go
📚 Learning: 2025-10-22T21:28:48.396Z
Learnt from: wolf31o2
Repo: blinklabs-io/dingo PR: 971
File: utxorpc/sync_test.go:339-339
Timestamp: 2025-10-22T21:28:48.396Z
Learning: utxorpc tests must pass github.com/blinklabs-io/gouroboros/ledger/common.Block to chain.Chain.AddBlock. They should create database/models.Block only as a storage row, then call models.Block.Decode() to obtain a ledger/common.Block for AddBlock and any ledger/protocol-facing logic.

Applied to files:

  • ledger/chainsync_test.go
📚 Learning: 2025-10-22T20:18:45.125Z
Learnt from: wolf31o2
Repo: blinklabs-io/dingo PR: 971
File: ledger/state_test.go:248-248
Timestamp: 2025-10-22T20:18:45.125Z
Learning: In tests, Chain.AddBlock must be given a gouroboros ledger.Block (not database/models.Block). Use a lightweight MockBlock (as in chain/chain_test.go) or call models.Block.Decode() when starting from stored rows.

Applied to files:

  • ledger/chainsync_test.go
🧬 Code graph analysis (4)
ledger/chainsync_test.go (6)
config/cardano/node.go (1)
  • CardanoNodeConfig (31-45)
ledger/state.go (2)
  • LedgerState (78-102)
  • LedgerStateConfig (58-68)
ledger/eras/byron.go (1)
  • ByronEraDesc (24-28)
ledger/eras/shelley.go (1)
  • ShelleyEraDesc (30-41)
ledger/eras/eras.go (1)
  • EraDesc (23-35)
database/database.go (1)
  • Database (45-50)
ledger/state_test.go (5)
config/cardano/node.go (1)
  • CardanoNodeConfig (31-45)
ledger/state.go (2)
  • LedgerState (78-102)
  • LedgerStateConfig (58-68)
ledger/eras/byron.go (1)
  • ByronEraDesc (24-28)
ledger/eras/shelley.go (1)
  • ShelleyEraDesc (30-41)
ledger/eras/eras.go (1)
  • EraDesc (23-35)
ledger/chainsync.go (2)
config/cardano/node.go (1)
  • CardanoNodeConfig (31-45)
database/types/types.go (1)
  • Rat (25-27)
ledger/state.go (3)
config/cardano/node.go (1)
  • CardanoNodeConfig (31-45)
database/plugin/log.go (1)
  • Logger (18-27)
database/types/types.go (2)
  • Rat (25-27)
  • Uint64 (54-54)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: go-test (1.24.x, ubuntu-latest)
  • GitHub Check: nilaway
  • GitHub Check: lint
  • GitHub Check: Analyze (go)

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ledger/chainsync.go (1)

274-314: Critical: Unreachable dead code and calculation issues.

  1. Unreachable dead code: Lines 279-281 return early for Byron era (Id == 0), making the Byron-specific branches at lines 300-301 and 307-308 unreachable. These conditions will never be true since we've already returned for Byron.

  2. Same calculation issues as handleEventChainsyncBlockHeader:

    • Missing nil check for ActiveSlotsCoeff.Rat (line 312)
    • Incorrect use of .Num().Uint64() instead of proper integer division (lines 310-314)
    • Missing validation for negative SecurityParam

Apply this diff:

 	// Calculate stability window
 	byronGenesis := ls.config.CardanoNodeConfig.ByronGenesis()
 	shelleyGenesis := ls.config.CardanoNodeConfig.ShelleyGenesis()
 	if byronGenesis == nil || shelleyGenesis == nil {
 		return nil, errors.New("could not get genesis config")
 	}
-	var securityParam uint64
-	// Use K parameter from Byron Genesis during Byron era, SecurityParam from Shelley Genesis for later eras
-	if ls.currentEra.Id == 0 { // Byron era ID is 0
-		securityParam = uint64(byronGenesis.ProtocolConsts.K)
-	} else {
-		securityParam = uint64(shelleyGenesis.SecurityParam)
-	}
-	// Calculate stability window: 3k/f for Shelley+ eras, just k for Byron
-	var stabilityWindow uint64
-	if ls.currentEra.Id == 0 { // Byron era
-		stabilityWindow = securityParam
-	} else {
-		stabilityWindow = new(big.Rat).Quo(
-			big.NewRat(int64(3*securityParam), 1),
-			shelleyGenesis.ActiveSlotsCoeff.Rat,
-		).Num().Uint64()
-	}
+	// Note: We're already in Shelley+ era due to early return at line 279
+	// Use SecurityParam from Shelley Genesis
+	k := shelleyGenesis.SecurityParam
+	if k < 0 {
+		return nil, fmt.Errorf("security param must be non-negative: %d", k)
+	}
+	securityParam := uint64(k)
+	
+	// Calculate stability window: 3k/f for Shelley+ eras
+	if shelleyGenesis.ActiveSlotsCoeff.Rat == nil {
+		return nil, errors.New("ActiveSlotsCoeff.Rat is nil")
+	}
+	result := new(big.Rat).Quo(
+		big.NewRat(int64(3*securityParam), 1),
+		shelleyGenesis.ActiveSlotsCoeff.Rat,
+	)
+	// Proper integer division: divide numerator by denominator
+	stabilityWindow := new(big.Int).Div(result.Num(), result.Denom()).Uint64()
🧹 Nitpick comments (1)
ledger/chainsync.go (1)

143-171: Consider extracting stability window calculation to a helper function.

The stability window calculation logic (era-aware security parameter retrieval + 3k/f formula for Shelley+) is duplicated between handleEventChainsyncBlockHeader and calculateEpochNonce. This duplication increases maintenance burden and the risk of inconsistencies.

Consider creating a helper method:

// calculateStabilityWindow returns the stability window based on the current era.
// For Byron era, returns k. For Shelley+ eras, returns 3k/f.
// Returns the default threshold if genesis data is unavailable or invalid.
func (ls *LedgerState) calculateStabilityWindow() uint64 {
	byronGenesis := ls.config.CardanoNodeConfig.ByronGenesis()
	shelleyGenesis := ls.config.CardanoNodeConfig.ShelleyGenesis()
	if byronGenesis == nil || shelleyGenesis == nil {
		return blockfetchBatchSlotThresholdDefault
	}
	
	var securityParam uint64
	if ls.currentEra.Id == 0 { // Byron era
		securityParam = uint64(byronGenesis.ProtocolConsts.K)
		return securityParam // Byron uses k directly
	}
	
	// Shelley+ eras
	k := shelleyGenesis.SecurityParam
	if k < 0 {
		ls.config.Logger.Warn("invalid negative security parameter", "k", k)
		return blockfetchBatchSlotThresholdDefault
	}
	securityParam = uint64(k)
	
	// Calculate 3k/f
	if shelleyGenesis.ActiveSlotsCoeff.Rat == nil {
		ls.config.Logger.Warn("ActiveSlotsCoeff.Rat is nil")
		return blockfetchBatchSlotThresholdDefault
	}
	
	result := new(big.Rat).Quo(
		big.NewRat(int64(3*securityParam), 1),
		shelleyGenesis.ActiveSlotsCoeff.Rat,
	)
	return new(big.Int).Div(result.Num(), result.Denom()).Uint64()
}

Then use it in both locations:

slotThreshold := ls.calculateStabilityWindow()

Also applies to: 298-314

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2b47f49 and 67e2d75.

📒 Files selected for processing (2)
  • ledger/chainsync.go (3 hunks)
  • ledger/state.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
ledger/state.go (1)
config/cardano/node.go (1)
  • CardanoNodeConfig (31-45)
ledger/chainsync.go (2)
config/cardano/node.go (1)
  • CardanoNodeConfig (31-45)
database/types/types.go (2)
  • Rat (25-27)
  • Uint64 (54-54)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: lint
  • GitHub Check: nilaway
  • GitHub Check: Analyze (go)
  • GitHub Check: go-test (1.24.x, ubuntu-latest)
🔇 Additional comments (2)
ledger/state.go (1)

597-623: LGTM! Era-aware security parameter retrieval is correctly implemented.

The implementation properly handles era-specific security parameter sources with appropriate error handling and validation. The check for negative k before casting to uint64 (lines 616-621) is essential to prevent incorrect large values.

ledger/chainsync.go (1)

40-40: LGTM! Clear naming improvement.

Renaming to blockfetchBatchSlotThresholdDefault better conveys that this is a fallback value when genesis data is unavailable.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
ledger/chainsync.go (1)

346-390: Same duplication and overflow issues as blockfetch threshold calculation.

This code segment duplicates the stability window calculation from lines 148-213. Please see my earlier comment on those lines suggesting extraction into a shared helper function.

Additionally, line 379 has the same potential uint64 overflow issue as line 193: computing 3 * securityParam before converting to big.Int could overflow if securityParam is large enough.

🧹 Nitpick comments (2)
ledger/state.go (1)

597-632: Suggest extracting era-aware security parameter retrieval into a helper function.

This security parameter retrieval logic (Byron K vs. Shelley SecurityParam with validation) is duplicated in ledger/chainsync.go at lines 148-172 and 346-362. Consider extracting it into a helper method on LedgerState, such as:

func (ls *LedgerState) getSecurityParam() (uint64, error) {
    if ls.currentEra.Id == 0 { // Byron era
        byronGenesis := ls.config.CardanoNodeConfig.ByronGenesis()
        if byronGenesis == nil {
            return 0, errors.New("failed to get Byron Genesis config")
        }
        k := byronGenesis.ProtocolConsts.K
        if k < 0 {
            return 0, fmt.Errorf("Byron K parameter must be non-negative: %d", k)
        }
        return uint64(k), nil // #nosec G115
    } else { // Shelley and later eras
        shelleyGenesis := ls.config.CardanoNodeConfig.ShelleyGenesis()
        if shelleyGenesis == nil {
            return 0, errors.New("failed to get Shelley Genesis config")
        }
        k := shelleyGenesis.SecurityParam
        if k < 0 {
            return 0, fmt.Errorf("security param must be non-negative: %d", k)
        }
        return uint64(k), nil // #nosec G115
    }
}

This would improve maintainability and ensure consistency across the codebase.

ledger/chainsync.go (1)

193-193: Apply defensive big.Int arithmetic for the security parameter multiplication to prevent theoretical uint64 overflow.

While Cardano protocol specifies no hardcoded maximum for the security parameter k and it's governance-changeable via on-chain updates, the current code multiplies 3 * securityParam in uint64 before converting to big.Int (ledger/chainsync.go lines 193 and 379). If securityParam ever exceeds ~6.1e18, this wraps silently and corrupts the stability window calculation—a bug the subsequent IsUint64() check won't catch.

Though mainnet k=2160 makes overflow practically impossible today, use big.Int throughout for robustness:

-numerator := new(big.Int).SetUint64(3 * securityParam)
+numerator := new(big.Int).SetUint64(securityParam)
+numerator.Mul(numerator, big.NewInt(3))

Apply this fix at both line 193 and line 379 in ledger/chainsync.go.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 67e2d75 and 6734d13.

📒 Files selected for processing (2)
  • ledger/chainsync.go (3 hunks)
  • ledger/state.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
ledger/state.go (1)
config/cardano/node.go (1)
  • CardanoNodeConfig (31-45)
ledger/chainsync.go (3)
config/cardano/node.go (1)
  • CardanoNodeConfig (31-45)
database/plugin/log.go (1)
  • Logger (18-27)
database/types/types.go (2)
  • Rat (25-27)
  • Uint64 (54-54)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: nilaway
  • GitHub Check: lint
  • GitHub Check: Analyze (go)
🔇 Additional comments (2)
ledger/chainsync.go (2)

39-40: LGTM!

The rename from blockfetchBatchSlotThreshold to blockfetchBatchSlotThresholdDefault clearly indicates this is a fallback value, which aligns well with the dynamic calculation logic introduced below.


215-219: LGTM!

The computed slotThreshold is correctly applied in the conditional to gate early return when the node is far from the upstream tip.

@wolf31o2 wolf31o2 force-pushed the feature/use-stability-window-for-blockfetch branch from 6734d13 to 8a15b9c Compare November 2, 2025 21:14
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ledger/state.go (1)

341-361: Avoid hard failure when Byron genesis is absent.

calculateEpochNonce already returns early for Byron (Line 327), so deployments that start in Shelley legitimately provide no Byron genesis. The new if byronGenesis == nil || shelleyGenesis == nil check makes those setups bail out with “could not get genesis config”, breaking epoch rollover. Please only require the genesis file for the era you actually use here.

Apply both hunks to keep compilation intact:

-	byronGenesis := ls.config.CardanoNodeConfig.ByronGenesis()
-	shelleyGenesis := ls.config.CardanoNodeConfig.ShelleyGenesis()
-	if byronGenesis == nil || shelleyGenesis == nil {
-		return nil, errors.New("could not get genesis config")
-	}
+	shelleyGenesis := ls.config.CardanoNodeConfig.ShelleyGenesis()
+	if shelleyGenesis == nil {
+		return nil, errors.New("failed to get Shelley genesis config")
+	}
@@
-	if ls.currentEra.Id == 0 { // Byron era ID is 0
-		k := byronGenesis.ProtocolConsts.K
+	if ls.currentEra.Id == 0 { // Byron era ID is 0
+		byronGenesis := ls.config.CardanoNodeConfig.ByronGenesis()
+		if byronGenesis == nil {
+			return nil, errors.New("failed to get Byron genesis config")
+		}
+		k := byronGenesis.ProtocolConsts.K
🧹 Nitpick comments (1)
ledger/chainsync.go (1)

144-213: Factor stability-window calculation into a helper.

This block duplicates the security-param extraction, ActiveSlotsCoeff validation, and overflow handling that calculateEpochNonce (Lines 346-390) already performs. Consider extracting a shared calculateStabilityWindow() helper returning (uint64, error) so both call sites stay in sync—here you can warn and fall back on error, while calculateEpochNonce can propagate it.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6734d13 and 8a15b9c.

📒 Files selected for processing (2)
  • ledger/chainsync.go (3 hunks)
  • ledger/state.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
ledger/state.go (1)
config/cardano/node.go (1)
  • CardanoNodeConfig (31-45)
ledger/chainsync.go (3)
config/cardano/node.go (1)
  • CardanoNodeConfig (31-45)
database/plugin/log.go (1)
  • Logger (18-27)
database/types/types.go (1)
  • Rat (25-27)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: nilaway
  • GitHub Check: lint
  • GitHub Check: go-test (1.24.x, ubuntu-latest)
  • GitHub Check: Analyze (go)
🔇 Additional comments (1)
ledger/state.go (1)

598-632: LGTM: era-aware k-window guard.

The non-negative checks and era split keep the cutoff aligned with the right security parameter without risking underflow.

@wolf31o2 wolf31o2 force-pushed the feature/use-stability-window-for-blockfetch branch from 8a15b9c to e3e3f6a Compare November 3, 2025 14:47
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8a15b9c and e3e3f6a.

📒 Files selected for processing (2)
  • ledger/chainsync.go (3 hunks)
  • ledger/state.go (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
ledger/state.go (3)
config/cardano/node.go (1)
  • CardanoNodeConfig (31-45)
database/plugin/log.go (1)
  • Logger (18-27)
database/types/types.go (1)
  • Rat (25-27)
ledger/chainsync.go (2)
config/cardano/node.go (1)
  • CardanoNodeConfig (31-45)
database/types/types.go (2)
  • Rat (25-27)
  • Uint64 (54-54)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: lint
  • GitHub Check: nilaway
  • GitHub Check: go-test (1.25.x, macos-latest)
  • GitHub Check: go-test (1.24.x, macos-latest)
  • GitHub Check: Analyze (go)

@wolf31o2 wolf31o2 force-pushed the feature/use-stability-window-for-blockfetch branch from e3e3f6a to 471d3d0 Compare November 3, 2025 15:30
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e3e3f6a and 471d3d0.

📒 Files selected for processing (2)
  • ledger/chainsync.go (3 hunks)
  • ledger/state.go (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
ledger/state.go (3)
config/cardano/node.go (1)
  • CardanoNodeConfig (31-45)
database/plugin/log.go (1)
  • Logger (18-27)
database/types/types.go (2)
  • Rat (25-27)
  • Uint64 (54-54)
ledger/chainsync.go (2)
config/cardano/node.go (1)
  • CardanoNodeConfig (31-45)
database/types/types.go (2)
  • Rat (25-27)
  • Uint64 (54-54)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: nilaway
  • GitHub Check: Analyze (go)

@wolf31o2 wolf31o2 force-pushed the feature/use-stability-window-for-blockfetch branch from 471d3d0 to 42827a4 Compare November 3, 2025 16:14
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 471d3d0 and 42827a4.

📒 Files selected for processing (2)
  • ledger/chainsync.go (3 hunks)
  • ledger/state.go (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
ledger/chainsync.go (2)
config/cardano/node.go (1)
  • CardanoNodeConfig (31-45)
database/types/types.go (2)
  • Rat (25-27)
  • Uint64 (54-54)
ledger/state.go (3)
config/cardano/node.go (1)
  • CardanoNodeConfig (31-45)
database/plugin/log.go (1)
  • Logger (18-27)
database/types/types.go (1)
  • Rat (25-27)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: nilaway
  • GitHub Check: Analyze (go)

@wolf31o2 wolf31o2 changed the title Use stability window instead of hard-coded slot threshold for blockfetch fix: use stability window for slot threshold Nov 3, 2025
@wolf31o2 wolf31o2 force-pushed the feature/use-stability-window-for-blockfetch branch from 42827a4 to a2f1e1f Compare November 3, 2025 18:37
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ledger/state.go (1)

312-323: Ceil the Shelley-era stability window in epoch nonce calculation

The same floor-based division shows up here, so the epoch-nonce stability window can undershoot the spec by one slot on networks where 3*k/f is non-integral. That can change which block we treat as “before the stability window.” Please switch to the ceiling form as in the ledger reference.

-	numerator := new(big.Int).SetUint64(3 * securityParam)
-	quotient := new(big.Int).Div(
-		new(big.Int).Mul(numerator, activeSlotsRat.Denom()),
-		activeSlotsRat.Num(),
-	)
+	numerator := new(big.Int).SetUint64(securityParam)
+	numerator.Mul(numerator, big.NewInt(3))
+	numerator.Mul(numerator, activeSlotsRat.Denom())
+	denominator := new(big.Int).Set(activeSlotsRat.Num())
+	quotient, remainder := new(big.Int).QuoRem(numerator, denominator, new(big.Int))
+	if remainder.Sign() != 0 {
+		quotient.Add(quotient, big.NewInt(1))
+	}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 42827a4 and a2f1e1f.

📒 Files selected for processing (2)
  • ledger/chainsync.go (3 hunks)
  • ledger/state.go (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
ledger/state.go (3)
config/cardano/node.go (1)
  • CardanoNodeConfig (31-45)
database/plugin/log.go (1)
  • Logger (18-27)
database/types/types.go (2)
  • Rat (25-27)
  • Uint64 (54-54)
ledger/chainsync.go (2)
config/cardano/node.go (1)
  • CardanoNodeConfig (31-45)
database/types/types.go (2)
  • Rat (25-27)
  • Uint64 (54-54)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: nilaway
  • GitHub Check: Analyze (go)

@wolf31o2 wolf31o2 force-pushed the feature/use-stability-window-for-blockfetch branch from a2f1e1f to 594a6f6 Compare November 3, 2025 18:54
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
ledger/chainsync.go (1)

272-323: Consider calling calculateStabilityWindow() to reduce duplication.

The stability window calculation logic here (lines 272-323) closely mirrors the implementation in calculateStabilityWindow() (state.go lines 409-495). The only difference is error handling: this function returns errors while calculateStabilityWindow() logs and falls back to the default.

While the past review comment suggested extracting this into a shared helper, the current implementation keeps them separate due to different error-handling semantics. Consider whether you could call calculateStabilityWindow() and convert a zero return value into an error, which would eliminate the duplication while preserving the error-propagation behavior needed here.

For example:

stabilityWindow := ls.calculateStabilityWindow()
if stabilityWindow == blockfetchBatchSlotThresholdDefault {
    return nil, errors.New("could not calculate stability window from genesis config")
}

However, this approach loses granular error messages. If you prefer to keep the detailed validation errors, the current duplication is acceptable for maintainability of distinct error paths.

ledger/state.go (1)

685-720: Consider extracting era-aware security parameter retrieval into a helper.

The era-aware security parameter logic (lines 685-720) is duplicated in calculateEpochNonce (chainsync.go lines 272-295). Both branches check for genesis availability, validate non-negative parameters, and select between Byron K and Shelley SecurityParam based on era.

Extracting a helper like getSecurityParam() (uint64, error) would eliminate this duplication and ensure consistent validation across both call sites.

For example:

func (ls *LedgerState) getSecurityParam() (uint64, error) {
    if ls.currentEra.Id == 0 { // Byron era
        byronGenesis := ls.config.CardanoNodeConfig.ByronGenesis()
        if byronGenesis == nil {
            return 0, errors.New("failed to get Byron Genesis config")
        }
        k := byronGenesis.ProtocolConsts.K
        if k <= 0 {
            return 0, fmt.Errorf("k parameter must be positive: %d", k)
        }
        return uint64(k), nil // #nosec G115
    }
    // Shelley+ eras
    shelleyGenesis := ls.config.CardanoNodeConfig.ShelleyGenesis()
    if shelleyGenesis == nil {
        return 0, errors.New("failed to get Shelley Genesis config")
    }
    k := shelleyGenesis.SecurityParam
    if k <= 0 {
        return 0, fmt.Errorf("security param must be positive: %d", k)
    }
    return uint64(k), nil // #nosec G115
}

This is optional since the duplication is limited and the code is clear as-is.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a2f1e1f and 594a6f6.

📒 Files selected for processing (2)
  • ledger/chainsync.go (3 hunks)
  • ledger/state.go (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
ledger/state.go (3)
config/cardano/node.go (1)
  • CardanoNodeConfig (31-45)
database/plugin/log.go (1)
  • Logger (18-27)
database/types/types.go (1)
  • Rat (25-27)
ledger/chainsync.go (2)
config/cardano/node.go (1)
  • CardanoNodeConfig (31-45)
database/types/types.go (2)
  • Rat (25-27)
  • Uint64 (54-54)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: nilaway
  • GitHub Check: Analyze (go)
🔇 Additional comments (3)
ledger/chainsync.go (2)

39-40: LGTM: Constant rename clarifies fallback behavior.

The rename from blockfetchBatchSlotThreshold to blockfetchBatchSlotThresholdDefault accurately reflects that this is now a fallback value when genesis data is unavailable or invalid.


143-146: LGTM: Dynamic stability window calculation properly integrated.

The block header handling now uses the calculated stability window instead of a hard-coded value, achieving the PR's objective of protocol compliance and era awareness.

ledger/state.go (1)

409-495: LGTM: Comprehensive stability window calculation with proper safeguards.

The calculateStabilityWindow() method correctly implements:

  • Era-aware parameter selection (Byron K vs. Shelley SecurityParam)
  • Validation of genesis availability, non-negative/non-zero parameters, and ActiveSlotsCoeff
  • Ceiling calculation for Shelley+ eras (3k/f rounded up) using proper big.Int arithmetic
  • Overflow checks before uint64 conversion
  • Fallback to default threshold on any validation failure

All issues raised in past review comments have been addressed.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 3, 2025

Note

Unit test generation is an Early Access feature. Expect some limitations and changes as we gather feedback and continue to improve it.


Generating unit tests... This may take up to 20 minutes.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 3, 2025

Creating a local commit for the generated unit tests...

The unit tests have been committed to the current branch. Commit ID: a43d73e32d77005b8841b7f138d5e093f883d3dd

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
ledger/chainsync.go (1)

296-323: Consolidate stability window calculation

calculateEpochNonce re-implements the stability-window math even though handleEventChainsyncBlockHeader now relies on ls.calculateStabilityWindow(). Keeping two hand-written copies makes it easy for the formulas or validations to drift apart the next time we tweak era handling or overflow checks. Please fold both call sites onto the same helper (or extract a shared internal routine that returns (uint64, error) so calculateEpochNonce can surface hard failures) and have the caller decide whether to log/fallback or bubble the error. That keeps the protocol constants in one place and prevents future regressions.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 594a6f6 and b73183f.

📒 Files selected for processing (1)
  • ledger/chainsync.go (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
ledger/chainsync.go (2)
config/cardano/node.go (1)
  • CardanoNodeConfig (31-45)
database/types/types.go (1)
  • Rat (25-27)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: nilaway
  • GitHub Check: Analyze (go)

@wolf31o2 wolf31o2 force-pushed the feature/use-stability-window-for-blockfetch branch from a43d73e to 3d97e2c Compare November 3, 2025 19:20
@wolf31o2
Copy link
Member Author

wolf31o2 commented Nov 3, 2025

@coderabbitai the tests for this are failing

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 3, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Run the tests to see what's failing
cd ledger
go test -v -run "Test" 2>&1 | head -200

Length of output: 12045


🏁 Script executed:

#!/bin/bash
# Get more test output to see the failures
cd ledger
go test -v -run "Test" 2>&1 | tail -400

Length of output: 4717


🏁 Script executed:

#!/bin/bash
# Look at the failing test code
cat ledger/chainsync_test.go | sed -n '680,720p'

Length of output: 889


🏁 Script executed:

#!/bin/bash
# Look at the calculateEpochNonce implementation to find the nil pointer issue
cat ledger/chainsync.go | sed -n '1,50p'

Length of output: 1649


🏁 Script executed:

#!/bin/bash
# Find and display the calculateEpochNonce function
ast-grep --pattern $'func (ls *LedgerState) calculateEpochNonce($$$) $$$'

Length of output: 6322


🏁 Script executed:

#!/bin/bash
# Look at the calculateStabilityWindow function in state.go
ast-grep --pattern $'func (ls *LedgerState) calculateStabilityWindow() $$$'

Length of output: 4114


🏁 Script executed:

#!/bin/bash
# Let me see the full test function to understand the intent
cat ledger/chainsync_test.go | sed -n '670,710p'

Length of output: 1216


🏁 Script executed:

#!/bin/bash
# Check if there are any test failures in state_test.go
cd ledger
go test -v -run "TestCalculateStabilityWindow" 2>&1

Length of output: 4951


@wolf31o2, I found the issue! The test TestCalculateEpochNonce_MissingByronGenesisInByronEra has incorrect expectations.

The problem is that in Byron era (era ID 0), the calculateEpochNonce function returns immediately at line 257-259 with nil, nil because Byron doesn't have epoch nonces. This early return happens before any genesis validation, so missing Byron genesis doesn't cause an error in this code path.

The test expects an error but gets nil, then tries to call err.Error() on line 703, causing the nil pointer panic.

Here's the fix for the test:

func TestCalculateEpochNonce_MissingByronGenesisInByronEra(t *testing.T) {
	shelleyGenesisJSON := `{
		"activeSlotsCoeff": 0.05,
		"securityParam": 432,
		"systemStart": "2022-10-25T00:00:00Z"
	}`

	cfg := &cardano.CardanoNodeConfig{
		ShelleyGenesisHash: "363498d1024f84bb39d3fa9593ce391483cb40d479b87233f868d6e57c3a400d",
	}
	if err := cfg.LoadShelleyGenesisFromReader(strings.NewReader(shelleyGenesisJSON)); err != nil {
		t.Fatalf("failed to load Shelley genesis: %v", err)
	}

	ls := &LedgerState{
		currentEra: eras.ByronEraDesc,
		currentEpoch: models.Epoch{
			EpochId:   1,
			StartSlot: 86400,
			Nonce:     []byte{0x01, 0x02, 0x03},
		},
		config: LedgerStateConfig{
			CardanoNodeConfig: cfg,
			Logger:            slog.New(slog.NewJSONHandler(io.Discard, nil)),
		},
		db: &database.Database{},
	}

	// Byron era should return nil nonce with no error (Byron doesn't have epoch nonces)
	// The function returns early before any genesis validation
	nonce, err := ls.calculateEpochNonce(nil, 86400)
	if err != nil {
		t.Errorf("expected no error for Byron era, got: %v", err)
	}
	if nonce != nil {
		t.Errorf("expected nil nonce for Byron era, got: %v", nonce)
	}
}

The fix changes the test to correctly verify that:

  1. No error is returned for Byron era (even with missing Byron genesis)
  2. Nonce is nil for Byron era (as Byron doesn't use epoch nonces)

This aligns with the actual behavior of the code where Byron era returns immediately without needing any genesis data.


🧠 Learnings used
Learnt from: wolf31o2
Repo: blinklabs-io/dingo PR: 971
File: utxorpc/sync_test.go:339-339
Timestamp: 2025-10-22T20:13:35.972Z
Learning: Unit tests under utxorpc should assert that models.Block.Decode() returns a github.com/blinklabs-io/gouroboros/ledger/common.Block, not rely on models.Block directly in protocol/ledger-facing logic.

Learnt from: wolf31o2
Repo: blinklabs-io/dingo PR: 971
File: utxorpc/sync_test.go:339-339
Timestamp: 2025-10-22T21:28:48.396Z
Learning: In utxorpc/sync_test.go, tests must not pass database/models.Block into chain.Chain.AddBlock. They should call models.Block.Decode() and pass the resulting github.com/blinklabs-io/gouroboros/ledger/common.Block to AddBlock.

Learnt from: wolf31o2
Repo: blinklabs-io/dingo PR: 971
File: utxorpc/sync_test.go:91-91
Timestamp: 2025-10-22T20:19:26.360Z
Learning: In utxorpc/sync_test.go, tests should not construct database/models.Block directly for sync server use. Instead, build a models.Block only as a container for CBOR and call models.Block.Decode() to obtain a github.com/blinklabs-io/gouroboros/ledger/common.Block (or the repository’s ledger.Block interface), and use that decoded value in the test.

@wolf31o2 wolf31o2 force-pushed the feature/use-stability-window-for-blockfetch branch from 3d97e2c to ad2f39f Compare November 3, 2025 21:53
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3d97e2c and ad2f39f.

📒 Files selected for processing (4)
  • ledger/chainsync.go (3 hunks)
  • ledger/chainsync_test.go (1 hunks)
  • ledger/state.go (2 hunks)
  • ledger/state_test.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • ledger/chainsync_test.go
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-10-22T20:13:35.164Z
Learnt from: wolf31o2
Repo: blinklabs-io/dingo PR: 971
File: ledger/state_test.go:56-56
Timestamp: 2025-10-22T20:13:35.164Z
Learning: In tests under ledger/state_test.go, PrimaryChain.AddBlock expects a "github.com/blinklabs-io/gouroboros/ledger/common".Block; use models.Block.Decode() to obtain that type before calling AddBlock.

Applied to files:

  • ledger/state_test.go
📚 Learning: 2025-10-22T20:19:25.277Z
Learnt from: wolf31o2
Repo: blinklabs-io/dingo PR: 971
File: ledger/state_test.go:434-434
Timestamp: 2025-10-22T20:19:25.277Z
Learning: In this repo’s tests, use models.Block.Decode() to obtain a ledger.Block before calling chain.Chain.AddBlock, since AddBlock expects a ledger.Block, while LedgerState.GetBlock returns a database/models.Block.

Applied to files:

  • ledger/state_test.go
📚 Learning: 2025-10-22T21:29:26.924Z
Learnt from: wolf31o2
Repo: blinklabs-io/dingo PR: 971
File: ledger/state_test.go:248-248
Timestamp: 2025-10-22T21:29:26.924Z
Learning: For tests under ledger/, prefer constructing a minimal ledger Block (MockBlock mirroring chain/chain_test.go) and pass it to Chain.AddBlock, rather than using database/models.Block or relying on models.Block.Decode().

Applied to files:

  • ledger/state_test.go
🧬 Code graph analysis (3)
ledger/chainsync.go (2)
config/cardano/node.go (1)
  • CardanoNodeConfig (31-45)
database/types/types.go (2)
  • Rat (25-27)
  • Uint64 (54-54)
ledger/state_test.go (5)
config/cardano/node.go (1)
  • CardanoNodeConfig (31-45)
ledger/state.go (2)
  • LedgerState (78-102)
  • LedgerStateConfig (58-68)
ledger/eras/byron.go (1)
  • ByronEraDesc (24-28)
ledger/eras/shelley.go (1)
  • ShelleyEraDesc (30-41)
ledger/eras/eras.go (1)
  • EraDesc (23-35)
ledger/state.go (3)
config/cardano/node.go (1)
  • CardanoNodeConfig (31-45)
database/plugin/log.go (1)
  • Logger (18-27)
database/types/types.go (1)
  • Rat (25-27)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: nilaway
  • GitHub Check: Analyze (go)

Comment on lines 214 to 259
t.Run("Missing Shelley genesis returns default", func(t *testing.T) {
cfg := &cardano.CardanoNodeConfig{}
byronGenesisJSON := `{
"protocolConsts": {
"k": 432,
"protocolMagic": 2
}
}`
if err := cfg.LoadByronGenesisFromReader(strings.NewReader(byronGenesisJSON)); err != nil {
t.Fatalf("failed to load Byron genesis: %v", err)
}

ls := &LedgerState{
currentEra: eras.ByronEraDesc,
config: LedgerStateConfig{
CardanoNodeConfig: cfg,
Logger: slog.New(slog.NewJSONHandler(io.Discard, nil)),
},
}

result := ls.calculateStabilityWindow()
if result != blockfetchBatchSlotThresholdDefault {
t.Errorf("expected default threshold %d, got %d", blockfetchBatchSlotThresholdDefault, result)
}
})
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix expected window when Shelley genesis is absent in Byron era

This test now asserts that we fall back to blockfetchBatchSlotThresholdDefault whenever the Shelley genesis is missing, even though the Byron calculation path doesn’t use it at all. Once we stop unconditionally requiring both genesis configs, the correct Byron-era behavior here is to still return k. Please update the test to expect the Byron security parameter (432 in this fixture) so we don’t bake in the regression.

🤖 Prompt for AI Agents
In ledger/state_test.go around lines 214-238, the test currently expects
blockfetchBatchSlotThresholdDefault when Shelley genesis is absent; update it to
expect the Byron security parameter instead (432 for the provided fixture) —
either assert the literal 432 or, better, read the value from the loaded Byron
genesis in cfg (the protocolConsts.k field) and compare that to the result so
the test reflects correct Byron-era behavior.

- Replace hard-coded blockfetchBatchSlotThreshold with dynamic calculation
- Use correct security parameters based on current era:
  * Byron era: K parameter from ByronGenesis.ProtocolConsts.K
  * Shelley+ eras: SecurityParam from ShelleyGenesis.SecurityParam
- Update stability window calculation in both chainsync and validation logic
- Calculate stability window as 3k/f for Shelley+ eras, k for Byron era
- Ensures blockfetch operations respect protocol-defined stability window

Fixes the TODO to calculate slot threshold from protocol params

Signed-off-by: Chris Gianelloni <wolf31o2@blinklabs.io>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@wolf31o2 wolf31o2 force-pushed the feature/use-stability-window-for-blockfetch branch from ad2f39f to 4a59bd9 Compare November 3, 2025 22:59
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.

Calculate blockfetch batch slot threshold from protocol params

2 participants