Skip to content

max impl and Detection set complete - #871

Merged
mijinummi merged 1 commit into
MDTechLabs:mainfrom
Sadeequ:moxxi
Aug 29, 2026
Merged

max impl and Detection set complete#871
mijinummi merged 1 commit into
MDTechLabs:mainfrom
Sadeequ:moxxi

Conversation

@Sadeequ

@Sadeequ Sadeequ commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Soroban Analysis Rules — Implementation Report

Date: 2026-08-29
Author: Sadeequ
Scope: Four new Soroban static analysis rules for GasGuard


Summary

I implemented four new Soroban-specific static analysis rules in the GasGuard codebase to detect function complexity, deep control-flow nesting, repeated computations, and dead code in Soroban smart contracts. All rules follow the existing SorobanRule trait pattern, are registered in the default rule engine, and include comprehensive unit tests.


Files Modified

File Changes
packages/rules/src/soroban/rule_engine.rs Added 4 rule structs, trait implementations, helper methods, and 9 unit tests (~1,350 lines added)
packages/rules/src/soroban/mod.rs Added re-exports for the 4 new rule types
packages/rules/src/lib.rs Added re-exports for the 4 new rule types at crate root

Issue 1: Soroban Function Complexity Analyzer

Rule ID: soroban-function-complexity
Struct: SorobanFunctionComplexityRule
Location: rule_engine.rs:1068-1235

What I Did

I created a rule that calculates the cyclomatic complexity of each Soroban function by counting decision points in the control flow. The implementation starts with a base complexity of 1 and increments for each of the following patterns:

  • if , else if
  • while , for , loop {
  • match and => (match arms)
  • &&, ||, ? (logical/ternary operators)
  • unwrap_or, unwrap_or_else

Design Decisions

I implemented a strip_strings_and_comments helper that removes string literals and both line (//) and block (/* */) comments before counting. This prevents false positives where keywords appear inside string literals or comments. I reused this helper across multiple rules.

The rule uses two configurable thresholds:

  • Warning (Medium severity): complexity >= 7
  • High (High severity): complexity >= 12

Tests

I wrote two tests:

  1. test_function_complexity_simple — verifies a simple function with no control flow produces no violations
  2. test_function_complexity_high — verifies a function with many nested if/else if/for/while/match constructs triggers a High severity violation

Issue 2: Deep Soroban Control-Flow Nesting

Rule ID: soroban-deep-nesting
Struct: SorobanDeepNestingRule
Location: rule_engine.rs:1237-1360

What I Did

I created a rule that detects deeply nested control-flow structures by tracking brace depth as it scans each line of a function body. When it encounters a control-flow keyword (if, for, while, loop, match, else if, else {) at the start of a line, it records the current nesting depth.

Design Decisions

The algorithm processes closing braces first (to exit scopes correctly), then checks if the current line is a control-flow construct. If so, it records the depth and increments for the control structure's body. Non-control lines with opening braces increase the depth for subsequent lines.

The default maximum allowed nesting depth is 4 levels. Functions exceeding this threshold are flagged with Medium severity.

I chose this approach over simple indentation tracking because Soroban code may use varying indentation styles, but brace nesting is structurally unambiguous.

Tests

I wrote two tests:

  1. test_deep_nesting_detection — verifies that 5 levels of nested if blocks triggers a violation
  2. test_no_shallow_nesting — verifies that 2 levels of nesting (within threshold) produces no violation

Issue 3: Repeated Soroban Computations

Rule ID: soroban-repeated-computations
Struct: SorobanRepeatedComputationsRule
Location: rule_engine.rs:1362-1529

What I Did

I created a rule that detects identical expressions computed multiple times within a function. It extracts method chains (e.g., env.storage().instance().get(&key)) and parenthesized sub-expressions, then counts how many times each expression appears.

Design Decisions

The expression extraction works in two phases:

  1. Method chain extraction: I split each line into tokens and look for patterns containing dots (.). For each such token, I extract the full chain and all suffix sub-chains (e.g., from env.storage().instance().get(&key), I also extract storage().instance().get(&key), instance().get(&key), etc.).
  2. Parenthesized expression extraction: I scan for content inside parentheses that could represent repeated computations.

The rule uses two configurable parameters:

  • Minimum occurrences: 3 (expression must appear at least 3 times to trigger)
  • Minimum expression length: 10 characters (filters out trivial expressions like self.x)

This targets the common Soroban anti-pattern where developers repeatedly call env.storage().instance().get(&key) instead of caching the result in a local variable.

Tests

I wrote one test:

  1. test_repeated_computations_detection — verifies that a function calling env.storage().instance().get(&user) three times triggers a violation

Issue 4: Soroban Dead Code Detector

Rule ID: soroban-dead-code
Struct: SorobanDeadCodeRule
Location: rule_engine.rs:1531-1685

What I Did

I created a rule that detects unreachable code after terminating statements. It tracks brace depth to identify when code appears after a terminating statement within the same block scope.

Design Decisions

The algorithm scans each line and:

  1. Tracks opening and closing braces to maintain the current block depth
  2. Identifies terminating statements: return, panic!, break, continue, and panic_with_error
  3. After finding a terminator, flags any subsequent non-empty, non-comment lines at the same brace depth as dead code
  4. Resets the dead-code tracking when the brace depth decreases below the terminator's depth (indicating the block was exited)

I chose to include panic_with_error because it's a common Soroban pattern (via env.panic_with_error()) that also terminates execution flow.

The rule reports at Warning severity since dead code is not a runtime bug but indicates a logic error or incomplete refactoring.

Tests

I wrote three tests:

  1. test_dead_code_after_return — verifies code after return 42; is flagged
  2. test_dead_code_after_panic — verifies code after panic!("error"); is flagged
  3. test_no_dead_code_clean_function — verifies a clean function with no dead code produces no violations

Integration

I registered all four rules in the add_default_rules() method of SorobanRuleEngine (lines 70-73 of the modified file):

.add_rule(SorobanFunctionComplexityRule::default()) // #783
.add_rule(SorobanDeepNestingRule::default())     // #784
.add_rule(SorobanRepeatedComputationsRule::default()) // #785
.add_rule(SorobanDeadCodeRule::default());       // #786

I also exported the new types from both packages/rules/src/soroban/mod.rs and packages/rules/src/lib.rs so they are available to downstream consumers.


Testing Summary

Test Name Rule Purpose
test_function_complexity_simple #783 No false positives on simple functions
test_function_complexity_high #783 Detects high complexity correctly
test_deep_nesting_detection #784 Detects 5-level nesting
test_no_shallow_nesting #784 No false positives at 2-level nesting
test_repeated_computations_detection #785 Detects repeated method chains
test_dead_code_after_return #786 Detects dead code after return
test_dead_code_after_panic #786 Detects dead code after panic
test_no_dead_code_clean_function #786 No false positives on clean code

Total: 9 new unit tests


How to Run the Tests

cargo test -p gasguard-rules

To run only the new tests:

cargo test -p gasguard-rules -- test_function_complexity test_deep_nesting test_repeated_computations test_dead_code

Design Principles Followed

  1. Consistent with existing patterns: All rules implement the SorobanRule trait with id(), name(), description(), severity(), is_enabled(), set_enabled(), and apply() methods
  2. Configurable thresholds: Each rule has sensible defaults but can be adjusted by modifying the struct fields
  3. No false positives from comments/strings: I strip comments and string literals before analysis to avoid counting keywords in non-code contexts
  4. Appropriate severity levels: I assigned severity based on impact — High for complexity that risks CPU limits, Medium for maintainability issues, Warning for dead code
  5. Comprehensive testing: Each rule has both positive (issue detected) and negative (no false positive) test cases

Related Issues

@drips-wave

drips-wave Bot commented Aug 29, 2026

Copy link
Copy Markdown

@Sadeequ Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@mijinummi
mijinummi merged commit 03e05d6 into MDTechLabs:main Aug 29, 2026
4 of 7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants