Skip to content

Conversation

@mateuszsikora
Copy link
Contributor

I added logic to load pvm gas cost tests and simple method to calculate gas cost of all basic blocks

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 10, 2025

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added per-block gas cost calculation, enabling clearer insight into gas usage across execution blocks.
  • Tests

    • Introduced a new gas cost test suite that validates computed block gas costs against expected values.
    • Integrated the gas cost tests into the existing test runner to support automated verification.

Walkthrough

Adds a new PVM gas-cost test type and runner, introduces a helper to parse/validate test inputs, integrates the runner into the W3F test harness, and implements Interpreter.calculateBlockGasCost to compute per-basic-block gas totals used by the new tests.

Changes

Cohort / File(s) Summary
W3F test helper: PVM gas cost
bin/test-runner/w3f/pvm-gas-cost.ts
New module defining PvmGasCostTest (with static fromJson) and runPvmGasCostTest. Validates input shape, initializes Interpreter, resets PVM with program and gas, computes block gas costs, and asserts expected vs. actual. Includes helper validators.
W3F runners integration
bin/test-runner/w3f/runners.ts
Imports PvmGasCostTest and runPvmGasCostTest; registers "gas-cost-tests" runner using PvmGasCostTest.fromJson and runPvmGasCostTest.
Interpreter gas-cost computation
packages/core/pvm-interpreter/interpreter.ts
Adds calculateBlockGasCost(): iterates code using mask, detects basic block boundaries, sums instruction gas via instructionGasMap, returns Record<string, number> keyed by block index.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor CLI as Test Runner CLI
  participant R as w3f/runners.ts
  participant T as PvmGasCostTest
  participant H as runPvmGasCostTest
  participant I as Interpreter

  CLI->>R: Load "gas-cost-tests"
  R->>T: fromJson(testContent)
  T-->>R: PvmGasCostTest
  R->>H: runPvmGasCostTest(testContent)
  H->>I: new Interpreter()
  H->>I: reset(program, 0, gas=tryAsGas(1000))
  H->>I: calculateBlockGasCost()
  I-->>H: blockGasCosts (Record<string, number>)
  H->>H: assert.deepStrictEqual(result, expected)
  H-->>R: test pass/fail
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • tomusdrw
  • skoszuta
  • DrEverr

Poem

I hop through blocks, count gas with care,
Nibbled bytes become costs to compare.
New runner drums a steady beat—
Interpreter maps each tiny feat.
Thump-thump! Tests pass, I twitch my nose,
Carrots for code where accuracy grows. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title Check ❓ Inconclusive The title “Block gas cost” is concise but too generic and does not clearly convey whether a new method or tests were added, lacking a verb or context to summarize the change. Consider revising the title to more specifically describe the change, for example “Add calculateBlockGasCost method and PVM block gas cost tests”.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed The description succinctly states that logic was added to load PVM gas cost tests and a method was implemented to calculate gas costs for basic blocks, which directly matches the changes in the PR.

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: 0

🧹 Nitpick comments (2)
bin/test-runner/w3f/pvm-gas-cost.ts (2)

18-32: Consider using a private constructor with a static factory method.

The class uses definite assignment assertions (!) for its properties. While this works, consider following the pattern of using a private constructor with a static factory method (like create()) for better type safety and initialization guarantees, especially since this class has a static fromJson field similar to classes with static Codec fields mentioned in the coding guidelines.

Apply this diff to improve type safety:

 export class PvmGasCostTest {
   static fromJson: FromJson<PvmGasCostTest> = {
     program: fromJson.uint8Array,
     block_gas_costs: json.fromAny((v) => {
       if (isBlockCostObject(v)) {
         return v;
       }

       throw new Error(`Expected an object, got ${typeof v} instead.`);
     }),
   };

-  program!: Uint8Array;
-  block_gas_costs!: Record<string, number>;
+  private constructor(
+    public readonly program: Uint8Array,
+    public readonly block_gas_costs: Record<string, number>,
+  ) {}
+
+  static create(program: Uint8Array, block_gas_costs: Record<string, number>): PvmGasCostTest {
+    return new PvmGasCostTest(program, block_gas_costs);
+  }
 }

Note: This would require updating the fromJson parser to use the factory method.


34-41: Hardcoded gas value may be insufficient for complex programs.

The test runner initializes the interpreter with a fixed gas value of 1000. This might be insufficient for programs with many instructions or high gas costs. Consider whether this value should be:

  1. Configurable via test input
  2. Calculated based on the program size
  3. Set to a sufficiently large value to ensure all blocks can be analyzed

Since calculateBlockGasCost() only analyzes the program structure without executing it, consider using a sufficiently large gas value or making it configurable:

 export async function runPvmGasCostTest(testContent: PvmGasCostTest) {
   const pvm = new Interpreter();
-  pvm.reset(testContent.program, 0, tryAsGas(1000));
+  // Use a large gas value since we're only analyzing structure, not executing
+  pvm.reset(testContent.program, 0, tryAsGas(1_000_000));

   const blockGasCosts = pvm.calculateBlockGasCost();

   assert.deepStrictEqual(blockGasCosts, testContent.block_gas_costs);
 }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a6eda68 and ad08631.

📒 Files selected for processing (3)
  • bin/test-runner/w3f/pvm-gas-cost.ts (1 hunks)
  • bin/test-runner/w3f/runners.ts (2 hunks)
  • packages/core/pvm-interpreter/interpreter.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
packages/core/**/*.ts

⚙️ CodeRabbit configuration file

packages/core/**/*.ts: Core packages must not import any JAM-related packages
(i.e. packages defined under packages/jam/**)

Files:

  • packages/core/pvm-interpreter/interpreter.ts
**/*.ts

⚙️ CodeRabbit configuration file

**/*.ts: as conversions must not be used. Suggest using tryAs conversion methods.

**/*.ts: Classes with static Codec field must have private constructor and static create method.

**/*.ts: Casting a bigint (or U64) using Number(x) must have an explanation comment why
it is safe.

**/*.ts: When making changes to code with comments containing links (in classes, constants, methods, etc.)
to graypaper.fluffylabs.dev, ensure those links point to the current version for this update.

Files:

  • packages/core/pvm-interpreter/interpreter.ts
  • bin/test-runner/w3f/runners.ts
  • bin/test-runner/w3f/pvm-gas-cost.ts
🧬 Code graph analysis (2)
bin/test-runner/w3f/runners.ts (2)
bin/test-runner/common.ts (1)
  • runner (15-21)
bin/test-runner/w3f/pvm-gas-cost.ts (2)
  • PvmGasCostTest (18-32)
  • runPvmGasCostTest (34-41)
bin/test-runner/w3f/pvm-gas-cost.ts (2)
packages/core/pvm-interpreter/interpreter.ts (1)
  • Interpreter (60-352)
packages/core/pvm-interpreter/gas.ts (1)
  • tryAsGas (18-19)
⏰ 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). (6)
  • GitHub Check: run (22.x)
  • GitHub Check: run (22.x)
  • GitHub Check: state_transition (22.x)
  • GitHub Check: test (22.x)
  • GitHub Check: benchmarks (22.x)
  • GitHub Check: e2e (22.x)
🔇 Additional comments (3)
bin/test-runner/w3f/pvm-gas-cost.ts (1)

6-17: LGTM! Helper functions are well-implemented.

The isPlainObject and isBlockCostObject validators correctly ensure type safety for the test input structure.

bin/test-runner/w3f/runners.ts (1)

42-42: LGTM! Test runner registration follows existing patterns.

The new gas-cost-tests runner is properly integrated into the test harness, following the same pattern as other test runners.

Also applies to: 64-64

packages/core/pvm-interpreter/interpreter.ts (1)

328-351: Verify initial block "0" cost in test data
Confirm that the test JSON loaded by bin/test-runner/w3f/pvm-gas-cost.ts includes (or omits) an entry for block "0" with a zero cost, ensuring calculateBlockGasCost aligns with expected behavior.

@github-actions
Copy link

View all
File Benchmark Ops
codec/bigint.compare.ts[0] compare custom 255742503.79 ±6.5% 1.15% slower
codec/bigint.compare.ts[1] compare bigint 258720927.71 ±5.49% fastest ✅
codec/bigint.decode.ts[0] decode custom 173720459.33 ±2.64% fastest ✅
codec/bigint.decode.ts[1] decode bigint 98219612.38 ±3.08% 43.46% slower
collections/map-set.ts[0] 2 gets + conditional set 116728.04 ±0.6% fastest ✅
collections/map-set.ts[1] 1 get 1 set 59942.07 ±0.27% 48.65% slower
hash/index.ts[0] hash with numeric representation 184.45 ±0.39% 18.05% slower
hash/index.ts[1] hash with string representation 101.91 ±1.46% 54.72% slower
hash/index.ts[2] hash with symbol representation 155.35 ±3.92% 30.98% slower
hash/index.ts[3] hash with uint8 representation 151.2 ±1.48% 32.82% slower
hash/index.ts[4] hash with packed representation 225.07 ±2.14% fastest ✅
hash/index.ts[5] hash with bigint representation 185.19 ±0.74% 17.72% slower
hash/index.ts[6] hash with uint32 representation 182.47 ±1.46% 18.93% slower
bytes/hex-from.ts[0] parse hex using Number with NaN checking 118853.22 ±1.76% 84.7% slower
bytes/hex-from.ts[1] parse hex from char codes 776775.84 ±1.59% fastest ✅
bytes/hex-from.ts[2] parse hex from string nibbles 529577.41 ±0.68% 31.82% slower
bytes/hex-to.ts[0] number toString + padding 282590.22 ±1.37% fastest ✅
bytes/hex-to.ts[1] manual 14558.51 ±1.21% 94.85% slower
codec/decoding.ts[0] manual decode 20821207.72 ±1.96% 85.69% slower
codec/decoding.ts[1] int32array decode 145500394.69 ±3.83% fastest ✅
codec/decoding.ts[2] dataview decode 142532466.58 ±2.97% 2.04% slower
codec/encoding.ts[0] manual encode 3052799.86 ±1.32% 14.27% slower
codec/encoding.ts[1] int32array encode 3561016.97 ±1.88% fastest ✅
codec/encoding.ts[2] dataview encode 3499301 ±1.55% 1.73% slower
math/add_one_overflow.ts[0] add and take modulus 226017179.68 ±5.98% fastest ✅
math/add_one_overflow.ts[1] condition before calculation 224624728.31 ±8.74% 0.62% slower
math/count-bits-u32.ts[0] standard method 72998014.15 ±1.74% 66.52% slower
math/count-bits-u32.ts[1] magic 218037599.91 ±5.57% fastest ✅
math/count-bits-u64.ts[0] standard method 1230701.57 ±0.64% 87.54% slower
math/count-bits-u64.ts[1] magic 9879684.92 ±0.69% fastest ✅
math/mul_overflow.ts[0] multiply and bring back to u32 256436176.94 ±5.22% fastest ✅
math/mul_overflow.ts[1] multiply and take modulus 249702425 ±6.39% 2.63% slower
math/switch.ts[0] switch 247584580.61 ±6.04% 0.89% slower
math/switch.ts[1] if 249813841.97 ±5.79% fastest ✅
logger/index.ts[0] console.log with string concat 6152663.69 ±52.73% fastest ✅
logger/index.ts[1] console.log with args 1447249.21 ±95.38% 76.48% slower
codec/view_vs_collection.ts[0] Get first element from Decoded 21294.96 ±1.37% 53.75% slower
codec/view_vs_collection.ts[1] Get first element from View 46038.63 ±1.77% fastest ✅
codec/view_vs_collection.ts[2] Get 50th element from Decoded 20821.75 ±1.53% 54.77% slower
codec/view_vs_collection.ts[3] Get 50th element from View 23962.35 ±2.62% 47.95% slower
codec/view_vs_collection.ts[4] Get last element from Decoded 21199.5 ±2.75% 53.95% slower
codec/view_vs_collection.ts[5] Get last element from View 13904.07 ±2.3% 69.8% slower
codec/view_vs_object.ts[0] Get the first field from Decoded 370301.73 ±1.73% 7.37% slower
codec/view_vs_object.ts[1] Get the first field from View 79464.49 ±1.25% 80.12% slower
codec/view_vs_object.ts[2] Get the first field as view from View 84688.93 ±1.19% 78.82% slower
codec/view_vs_object.ts[3] Get two fields from Decoded 399783.5 ±1.5% fastest ✅
codec/view_vs_object.ts[4] Get two fields from View 64804.03 ±1.08% 83.79% slower
codec/view_vs_object.ts[5] Get two fields from materialized from View 143214.51 ±1.12% 64.18% slower
codec/view_vs_object.ts[6] Get two fields as views from View 64281.44 ±1.01% 83.92% slower
codec/view_vs_object.ts[7] Get only third field from Decoded 381273.88 ±1.24% 4.63% slower
codec/view_vs_object.ts[8] Get only third field from View 84398.17 ±1.2% 78.89% slower
codec/view_vs_object.ts[9] Get only third field as view from View 78936.61 ±1.02% 80.26% slower
bytes/compare.ts[0] Comparing Uint32 bytes 15613.87 ±2.64% 24.54% slower
bytes/compare.ts[1] Comparing raw bytes 20690.6 ±2.31% fastest ✅
collections/map_vs_sorted.ts[0] Map 304347.4 ±0.19% fastest ✅
collections/map_vs_sorted.ts[1] Map-array 102900.42 ±0.22% 66.19% slower
collections/map_vs_sorted.ts[2] Array 59845.59 ±2.47% 80.34% slower
collections/map_vs_sorted.ts[3] SortedArray 198002.4 ±0.28% 34.94% slower
hash/blake2b.ts[0] our hasher 2.09 ±7.66% fastest ✅
hash/blake2b.ts[1] blake2b js 0.05 ±2.3% 97.61% slower
crypto/ed25519.ts[0] native crypto 6.1 ±15.83% 80.1% slower
crypto/ed25519.ts[1] wasm lib 10.88 ±0.03% 64.51% slower
crypto/ed25519.ts[2] wasm lib batch 30.66 ±0.47% fastest ✅

Benchmarks summary: 63/63 OK ✅

@tomusdrw tomusdrw merged commit b6e3410 into main Oct 13, 2025
16 checks passed
@tomusdrw tomusdrw deleted the ms-block-gas-cost branch October 13, 2025 08:53
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.

3 participants