Skip to content

feat(payload): add shared resource metering evaluator - #4673

Open
niran wants to merge 1 commit into
mainfrom
niran/resource-metering-evaluator
Open

feat(payload): add shared resource metering evaluator#4673
niran wants to merge 1 commit into
mainfrom
niran/resource-metering-evaluator

Conversation

@niran

@niran niran commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add a shared, versioned resource-metering schedule and decision model used by both payload builders.
  • Per-dimension dryRun (omitted = enforce), fail-open arithmetic, and transaction-versus-block throttle scope.
  • Move metering provider and rejection-cache ownership into the payload crate, keeping builder-core re-exports.

Stacked replacement for the shared evaluator slice of #4428. Later PRs in this stack add observations, native admission, Flashblocks admission, and wall-clock retirement.

Test plan

  • cargo test --lib -p base-execution-payload-builder
  • Confirm later stack PRs still compile against this evaluator API

type=routine
risk=low
impact=sev5

Define one versioned schedule and decision model for both payload builders, including per-dimension dry-run, fail-open arithmetic, and transaction-versus-block scope. Move provider and rejection-cache ownership into the payload crate while preserving builder-core re-exports.
@cb-heimdall

Copy link
Copy Markdown
Collaborator

🟡 Heimdall Review Status

Requirement Status More Info
Reviews 🟡 0/1
Denominator calculation
Show calculation
1 if user is bot 0
1 if user is external 0
2 if repo is sensitive 0
From .codeflow.yml 1
Additional review requirements
Show calculation
Max 0
0
From CODEOWNERS 0
Global minimum 0
Max 1
1
1 if commit is unverified 0
Sum 1

/// Independently budgeted resource dimensions.
pub dimensions: Vec<ResourceMeteringDimension>,
#[serde(skip)]
operation_index: HashMap<String, Vec<(usize, u64, u64)>>,

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.

nit: operation_index uses HashMap (non-deterministic iteration order). This is fine here since evaluate() only does key lookups (not iteration), but worth noting that the Serialize derive on ResourceMeteringSchedule will skip this field (#[serde(skip)]), so serialization determinism is preserved. If a future change iterates operation_index in a consensus-sensitive path, it should switch to BTreeMap.

Comment on lines +149 to +153
);
if decision.should_exclude() {
self.record_decision(tx_hash, &decision);
}
(simulated, decision)

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.

Note: predict only records decisions where should_exclude() is true (enforced throttles). Dry-run throttle observations at the prediction stage are silently dropped — the metric/log won't fire until decide_executed runs after execution. This means if a caller uses predict to skip execution entirely (which it can't today since should_exclude() is false for dry-run), the observation would be lost.

This is fine given the current flow where CalculationFailed and dry-run Throttle both proceed to execution, but it's worth documenting explicitly that predict intentionally under-reports dry-run observations, since a future caller might expect the metrics to be recorded here regardless of the exclude decision.

@github-actions

Copy link
Copy Markdown
Contributor

Review Summary

PR: feat(payload): add shared resource metering evaluator

This PR introduces a versioned resource-metering schedule and decision model (ResourceMeteringSchedule, ResourceMeteringConfig) into the base-execution-payload-builder crate, moving the MeteringProvider trait, RejectionCache, and related types from builder-core to the payload crate. The change is well-structured with thorough test coverage.

Block-Production Safety Assessment

This PR is block-production-sensitive (touches metering and payload assembly paths). After reviewing against the block production review guide:

  • Fail-open design is consistently applied: CalculationFailed never excludes transactions, arithmetic overflow in add_to / apply_accounted_usage is caught and fails open, and missing meter data produces zero usage. This means a misconfigured schedule cannot halt payload construction.
  • Dry-run dimension support: Dimensions can be observed without excluding, providing a safe rollout mechanism.
  • No new panics in hot paths: All arithmetic uses checked_* operations. No unwrap()/expect() in non-test code paths.
  • Schedule loading is startup-only: from_file reads from disk only in from_parts, not during block building.
  • No new I/O boundaries: The evaluator operates in-process on data already available to the builder.

No critical block-production findings.

Minor Findings

  1. HashMap in operation_index (resource_metering.rs:45): Safe for current use (key lookups only, #[serde(skip)]), but worth noting for future maintainers if iteration is ever added in a deterministic context.

  2. predict observation gap (config.rs:149-153): Dry-run throttle observations at prediction time are intentionally not recorded — only enforced excludes fire the metric/log. The deferred recording in decide_executed covers this, but the asymmetry could surprise future callers.

What Looks Good

  • Comprehensive validation at schedule compile time (name constraints, duplicate detection, noop checks, limit ordering)
  • Atomic add_to semantics preventing partial cumulative writes
  • Clean separation between file-format DTOs and runtime types
  • Thorough test coverage including overflow, fail-open, dry-run, and edge cases
  • Bounded metric cardinality (dimension names from operator-controlled schedule, max 128)

@github-actions

Copy link
Copy Markdown
Contributor

Base Std historical fork tests

Fork Result Passed Failed Skipped base/base base-anvil base-std
Beryl pass 616 0 13 d8346a0d 8d0f5b8a 4658f1b7
Cobalt pass 721 0 14 d8346a0d 9df661bc e30b3421

View run

@github-actions

Copy link
Copy Markdown
Contributor

Caution

This PR may regress performance. 1 benchmark(s) slower by more than 10% beyond the noise band: execution/Open 1024 nodes - 4096 nodes (+49.1%).

Benchmark results (advisory)

Median time on the PR head versus the base branch, measured on the same host. Wall-clock, so a change is only flagged when it clears ±10% and the confidence intervals do not overlap. Only benchmarks past the ±10% threshold (plus new or dropped ones) are listed. This check never blocks a merge.

Benchmark Base Head Δ median
execution/Delete 16 nodes - 65,536 nodes 5.38 ms 4.47 ms -16.9% ✅ faster
execution/Insertion - 65,536 nodes 34.88 ms 31.33 ms -10.2% ✅ faster
execution/Open 1024 nodes - 4096 nodes 37.80 µs 56.34 µs +49.1% ⚠️ slower

46 benchmark(s) within ±10% omitted.

View run · Re-run benchmarks

@niran
niran requested a review from 0x00101010 August 25, 2026 22:43
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.

2 participants