Skip to content

Temporal Tariff State Calculator Integer Precision Loss in Time-Weighted Rate Averaging #2

Description

@elizabetheonoja-art

Temporal Tariff State Calculator Integer Precision Loss in Time-Weighted Rate Averaging

Problem Statement

The contracts/src/tariff/temporal_calculator.rs module computes time-weighted average rates for volumetric resource billing across temporal windows (peak/off-peak/Shoulder). The calculate_weighted_rate() function at line 72 performs sum(rate_i * duration_i) / total_duration where all values are u128. For a 30-day billing window with 15-minute granularity (2880 intervals), duration_i is stored in seconds. The product rate_i * duration_i can overflow u128 when rate_i has 18 decimal places (Soroban token standard) and duration_i = 2592000 (30 days in seconds). Specifically, rate = 500000000000000000000 (500 tokens at 18 decimals) × 2592000 = 1.296e27, which exceeds u128::MAX / 2, causing intermediate overflow before division. The truncated result produces a 15% error in the final weighted average for peak-period billing.

State Invariants & Parameters

  • MAX_DECIMALS: 18
  • MAX_TARIFF_INTERVALS: 2880 (30 days at 15-min granularity)
  • INTERVAL_DURATION_UNITS: seconds (u64)
  • u128::MAX: 3.4e38
  • Current overflow threshold: rate * duration > 1.7e38
  • Invariant: ∀ intervals: Σ(rate_i × duration_i) / total_duration ∈ [min_rate, max_rate]

Affected Code Paths

  • contracts/src/tariff/temporal_calculator.rs:65-100 — Weighted rate calculation multiplication overflow
  • contracts/src/tariff/tariff_schedule.rs:40-80 — Schedule loading that feeds into calculator
  • contracts/src/tariff/tests/temporal_tests.rs — No overflow edge-case tests at max intervals

Resolution Blueprint

  1. Implement a checked_weighted_average() using u128::checked_mul() with early return on overflow, falling back to a div-then-mul strategy: rate_i / total_duration * duration_i which maintains precision for rate_i / total_duration using Decimal128 with a 38-digit intermediate scale.
  2. Add a Decimal128 wrapper struct in contracts/src/tariff/decimal128.rs that implements mul() and div() with 38-digit internal precision (stored as (u128 mantissa, i8 scale)) and rounds using ROUND_HALF_UP.
  3. Pre-validate interval data at tariff creation time: require!(rate_i.checked_mul(duration_i).is_some(), "rate*interval overflow") — reject tariff schedules that exceed the safe computation range.
  4. Add property-based tests covering rate ∈ [1, 10^18], duration ∈ [60, 2592000], and interval_count ∈ [1, 2880], verifying relative error < 10^-15.
  5. Update contracts/docs/specs/tariff-precision.md with the decimal scaling strategy and overflow safety guarantees.

Labels

  • Complexity: Hardcore
  • Layer: Core-Engine
  • Type: Race-Condition

Metadata

Metadata

Assignees

Labels

Complexity: HardcoreIssues requiring deep systems-level engineering rigorGrantFox OSSIssue tracked in GrantFox OSSLayer: Core-EngineCore contract engine layerMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial CampaignCampaign: Official CampaignType: Race-ConditionConcurrency and race condition related issues

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions