@@ -36,9 +36,8 @@ const (
3636 // This prevents us exceeding the configured recv queue size in the block-fetch protocol
3737 blockfetchBatchSize = 500
3838
39- // TODO: calculate from protocol params
40- // Number of slots from upstream tip to stop doing blockfetch batches
41- blockfetchBatchSlotThreshold = 2500 * 20
39+ // Default/fallback slot threshold for blockfetch batches
40+ blockfetchBatchSlotThresholdDefault = 2500 * 20
4241
4342 // Timeout for updates on a blockfetch operation. This is based on a 2s BatchStart
4443 // and a 2s Block timeout for blockfetch
@@ -141,8 +140,10 @@ func (ls *LedgerState) handleEventChainsyncBlockHeader(e ChainsyncEvent) error {
141140 }
142141 // Wait for additional block headers before fetching block bodies if we're
143142 // far enough out from upstream tip
143+ // Use security window as slot threshold if available
144+ slotThreshold := ls .calculateStabilityWindow ()
144145 if e .Point .Slot < e .Tip .Point .Slot &&
145- (e .Tip .Point .Slot - e .Point .Slot > blockfetchBatchSlotThreshold ) &&
146+ (e .Tip .Point .Slot - e .Point .Slot > slotThreshold ) &&
146147 (headerCount + 1 ) < allowedHeaderCount {
147148 return nil
148149 }
@@ -267,18 +268,59 @@ func (ls *LedgerState) calculateEpochNonce(
267268 return genesisHashBytes , nil
268269 }
269270 // Calculate stability window
270- byronGenesis := ls .config .CardanoNodeConfig .ByronGenesis ()
271271 shelleyGenesis := ls .config .CardanoNodeConfig .ShelleyGenesis ()
272- if byronGenesis == nil || shelleyGenesis == nil {
273- return nil , errors .New ("could not get genesis config" )
272+ if shelleyGenesis == nil {
273+ return nil , errors .New ("could not get Shelley genesis config" )
274+ }
275+ var securityParam uint64
276+ // Use K parameter from Byron Genesis during Byron era, SecurityParam from Shelley Genesis for later eras
277+ if ls .currentEra .Id == 0 { // Byron era ID is 0
278+ byronGenesis := ls .config .CardanoNodeConfig .ByronGenesis ()
279+ if byronGenesis == nil {
280+ return nil , errors .New ("could not get Byron genesis config" )
281+ }
282+ k := byronGenesis .ProtocolConsts .K
283+ if k < 0 {
284+ return nil , fmt .Errorf ("k parameter must be non-negative: %d" , k )
285+ }
286+ // Safe conversion: K is non-negative
287+ securityParam = uint64 (k ) // #nosec G115
288+ } else {
289+ secParam := shelleyGenesis .SecurityParam
290+ if secParam < 0 {
291+ return nil , fmt .Errorf ("security param must be non-negative: %d" , secParam )
292+ }
293+ // Safe conversion: SecurityParam is non-negative
294+ securityParam = uint64 (secParam ) // #nosec G115
295+ }
296+ // Calculate stability window: 3k/f for Shelley+ eras, just k for Byron
297+ var stabilityWindow uint64
298+ if ls .currentEra .Id == 0 { // Byron era
299+ stabilityWindow = securityParam
300+ } else {
301+ // Validate ActiveSlotsCoeff before using it
302+ if shelleyGenesis .ActiveSlotsCoeff .Rat == nil {
303+ return nil , errors .New ("empty ActiveSlotsCoeff" )
304+ }
305+ activeSlotsRat := shelleyGenesis .ActiveSlotsCoeff .Rat
306+ // Check for division by zero
307+ if activeSlotsRat .Num ().Sign () == 0 {
308+ return nil , errors .New ("divide by zero" )
309+ }
310+ // Compute stability window: floor((3 * securityParam) / f)
311+ // Using integer arithmetic to avoid floating point precision issues
312+ numerator := new (big.Int ).SetUint64 (3 * securityParam )
313+ quotient := new (big.Int ).Div (
314+ new (big.Int ).Mul (numerator , activeSlotsRat .Denom ()),
315+ activeSlotsRat .Num (),
316+ )
317+
318+ // Check if result fits in uint64
319+ if ! quotient .IsUint64 () {
320+ return nil , errors .New ("stability window calculation result too large" )
321+ }
322+ stabilityWindow = quotient .Uint64 ()
274323 }
275- stabilityWindow := new (big.Rat ).Quo (
276- big .NewRat (
277- int64 (3 * byronGenesis .ProtocolConsts .K ),
278- 1 ,
279- ),
280- shelleyGenesis .ActiveSlotsCoeff .Rat ,
281- ).Num ().Uint64 ()
282324 var stabilityWindowStartSlot uint64
283325 if epochStartSlot > stabilityWindow {
284326 stabilityWindowStartSlot = epochStartSlot - stabilityWindow
0 commit comments