Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,22 @@ dotnet_diagnostic.IDE0011.severity = warning
# Require embedded statements on their own line
csharp_style_allow_embedded_statements_on_same_line_experimental = false:warning
dotnet_diagnostic.IDE2001.severity = warning

# --- Member Ordering (Treasure.Analyzers) ---
dotnet_diagnostic.Treasure0001.severity = warning

# Exclude file with conversion operator - Treasure.Analyzers bug
[**/ArbosStorageUpdateResult.cs]
dotnet_diagnostic.Treasure0001.severity = none

# --- Explicit Types (no var) ---
dotnet_diagnostic.IDE0008.severity = warning
csharp_style_var_for_built_in_types = false:warning
csharp_style_var_when_type_is_apparent = false:warning
csharp_style_var_elsewhere = false:warning

# --- Access Modifiers Required ---
dotnet_diagnostic.IDE0040.severity = warning
dotnet_style_require_accessibility_modifiers = always:warning


61 changes: 61 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Copilot Code Review Instructions for Nethermind Arbitrum

## Project Context

This is a C# implementation of the Arbitrum execution client as a plugin for Nethermind Ethereum client. Code correctness and style consistency are critical for blockchain consensus.

## Code Style Rules (ENFORCE STRICTLY)

### Type Declarations
- **REJECT** any use of `var` keyword - always require explicit types
- **REJECT** missing access modifiers on class members

```csharp
// CORRECT
Address account = new("0x123...");
List<Transaction> txs = new();

// WRONG - flag these
var account = new Address("0x123...");
var txs = new List<Transaction>();
```

### Member Ordering (CRITICAL)
Flag violations of this order within classes:
1. Constants (`const`)
2. Static fields
3. Instance fields
4. Constructors
5. Properties
6. Methods

### Access Modifier Ordering
Within each member category, order by access level:
1. `public`
2. `internal`
3. `protected`
4. `private`

### Braces
- Single-statement blocks should NOT have braces
- Multi-statement blocks MUST have braces

```csharp
// CORRECT
if (condition)
DoSomething();

// WRONG
if (condition)
{
DoSomething();
}
```

## Performance Requirements

Flag these anti-patterns:
- Unnecessary allocations in loops or hot paths
- Large structs passed by value instead of `in` or `ref`
- Missing `Span<T>` or `Memory<T>` for buffer operations
- LINQ in performance-critical code paths
93 changes: 93 additions & 0 deletions .github/instructions/production-code.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
---
applyTo:
- "src/Nethermind.Arbitrum/**/*.cs"
excludeAgent:
- "coding-agent"
---

# Production Code Review Instructions

## Member Ordering (CRITICAL - ALWAYS CHECK)

Every class MUST have members in this exact order:

```csharp
public class Example
{
// 1. CONSTANTS (const) - public first, then private
public const int MaxValue = 100;
private const string DefaultName = "Unknown";

// 2. STATIC FIELDS - public first, then private
public static readonly ILogger SharedLogger;
private static readonly object s_lock = new();

// 3. INSTANCE FIELDS - public first, then private
public readonly Address ContractAddress;
private readonly IBlockTree _blockTree;
private int _counter;

// 4. CONSTRUCTORS
public Example(IBlockTree blockTree) { }

// 5. PROPERTIES - public first, then private
public string Name { get; }
private int InternalCounter => _counter;

// 6. METHODS - public first, then private
public void Process() { }
private void Helper() { }
}
```

**REJECT** code where:
- Fields appear after constructors
- Properties appear before fields
- Methods appear before properties
- Private members appear before public members in same category

## Type Declarations (CRITICAL)

**REJECT** any use of `var`:

```csharp
// REJECT
var address = new Address("0x123");
var transactions = new List<Transaction>();
var result = GetResult();

// REQUIRE
Address address = new("0x123");
List<Transaction> transactions = new();
MyResultType result = GetResult();
```

## Access Modifiers

**REJECT** missing access modifiers:

```csharp
// REJECT
class MyClass { }
readonly ILogger _logger;

// REQUIRE
public class MyClass { }
private readonly ILogger _logger;
```

## Execution (src/Nethermind.Arbitrum/Execution/**)

Additional checks for execution files:
- Gas deduction order is critical - flag any reordering of gas operations
- Flag changes to refund calculations
- Flag any state modification that could be non-deterministic

## Performance

**Flag** these patterns:
- Allocations inside loops
- LINQ in hot paths (prefer foreach)
- Large structs passed by value
- String concatenation in loops (use StringBuilder)
- Missing `readonly` on fields that could be readonly
118 changes: 118 additions & 0 deletions .github/instructions/test-code.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
---
applyTo:
- "src/Nethermind.Arbitrum.Test/**/*.cs"
- "**/Test/**/*.cs"
- "**/*Tests.cs"
- "**/*Test.cs"
---

# Test Code Review Instructions

## Test Naming Convention (CRITICAL - ALWAYS ENFORCE)

**Pattern: `MethodName_Condition_ExpectedResult`**

Every test method MUST have exactly THREE parts separated by underscores:
1. Method/feature being tested
2. State/condition/input
3. Expected behavior/result

### CORRECT Examples (approve these patterns)
```csharp
GetBalance_ValidAccountAndEnoughGas_ReturnsBalance
GetBalance_InsufficientGas_ThrowsOutOfGasException
GetBalance_NonExistentAccount_ReturnsZero
DigestMessage_ValidMessage_ProducesBlock
ParseInput_MalformedData_ThrowsDecodingException
```

### WRONG Examples (REJECT and request fix)
```csharp
// Missing condition part
GetBalance_ReturnsBalance // REJECT: missing condition
TestGetBalance // REJECT: not following pattern

// Informal/verbose language
GetBalance_DoesntHaveEnoughBalance_Fails // REJECT: use "InsufficientBalance"
GetBalance_WhenAccountDoesNotExist_Returns0 // REJECT: use "NonExistentAccount"

// Extra prefixes
Should_GetBalance_WhenValid_ReturnBalance // REJECT: no "Should" prefix
Test_GetBalance_Returns_Value // REJECT: no "Test" prefix

// Vague naming
BalanceTest // REJECT: not descriptive
TestMethod1 // REJECT: meaningless name
```

### Naming Guidelines

**For conditions, use concise terms:**
- `ValidInput`, `InvalidInput`, `MalformedData`
- `EnoughGas`, `InsufficientGas`, `ZeroGas`
- `ExistingAccount`, `NonExistentAccount`
- `EmptyArray`, `NullParameter`, `ZeroValue`

**For results, use action verbs:**
- `ReturnsValue`, `ReturnsZero`, `ReturnsNull`, `ReturnsEmpty`
- `ThrowsException`, `ThrowsArgumentException`
- `ProducesBlock`, `UpdatesState`, `EmitsEvent`
- `Succeeds`, `Fails`

## Test Structure (AAA Pattern)

Require clear Arrange/Act/Assert sections:

```csharp
[Test]
public void GetBalance_ValidAccount_ReturnsBalance()
{
Address account = new("0x123...");
UInt256 expectedBalance = 1000;

UInt256 result = sut.GetBalance(account);

Assert.That(result, Is.EqualTo(expectedBalance));
}
```

## Assertion Rules (CRITICAL)

**REJECT** these assertion patterns:
```csharp
// WRONG - no range comparisons
Assert.That(value, Is.GreaterThan(0));
Assert.That(value, Is.LessThan(100));
Assert.That(value, Is.AtLeast(1));

// CORRECT - exact values only
Assert.That(value, Is.EqualTo(42));
Assert.That(value, Is.EqualTo(expectedValue));
```

**Flag** tests with:
- Multiple unrelated assertions
- Branching logic (if/switch)
- Shared mutable state between tests
- Dependencies on test execution order

## Test Organization

**Flag** these patterns:
- `[SetUp]` or `[TearDown]` methods (prefer self-contained tests)
- Private helper methods (should be in test infrastructure)
- Test classes with dependencies on other test classes

## Type Declarations in Tests

Same as production code - **REJECT** `var` keyword:

```csharp
// CORRECT
IWorldState worldState = TestWorldStateFactory.CreateForTest();
Address account = new("0x123...");

// WRONG
var worldState = TestWorldStateFactory.CreateForTest();
var account = new Address("0x123...");
```
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0.x'
dotnet-version: '10.0.x'

- name: Build ${{ matrix.project }}
run: dotnet build ${{ matrix.project }} --configuration Release
Expand All @@ -51,7 +51,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0.x'
dotnet-version: '10.0.x'

- name: Install dotnet-format
run: dotnet tool install -g dotnet-format
Expand All @@ -72,7 +72,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0.x'
dotnet-version: '10.0.x'

- name: Run tests with Arbitrum-only coverage (Cobertura)
run: |
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,8 @@ coverage-report: ## Generate and open HTML coverage report in browser

format: ## Format code using dotnet format
@echo "Formatting Nethermind Arbitrum code..."
dotnet format src/Nethermind.Arbitrum/Nethermind.Arbitrum.csproj
dotnet format src/Nethermind.Arbitrum.Test/Nethermind.Arbitrum.Test.csproj
dotnet format src/Nethermind.Arbitrum/Nethermind.Arbitrum.csproj --exclude src/Nethermind/
dotnet format src/Nethermind.Arbitrum.Test/Nethermind.Arbitrum.Test.csproj --exclude src/Nethermind/

help: ## Show this help message
@echo "Available targets:"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class ArbosGenesisLoaderTests
public void Load_FullChainSimulationAtV32_ProducesCorrectHash()
{
IWorldState worldState = TestWorldStateFactory.CreateForTest();
using var worldStateDisposer = worldState.BeginScope(IWorldState.PreGenesis);
using IDisposable worldStateDisposer = worldState.BeginScope(IWorldState.PreGenesis);

Block genesisBlock = ArbOSInitialization.Create(worldState);

Expand Down
Loading
Loading