Skip to content

Commit 32ff022

Browse files
committed
Merge remote-tracking branch 'upstream/master' into glamsterdam-devnet-6
# Conflicts: # src/Nethermind/Ethereum.Blockchain.Pyspec.Test/Constants.cs
2 parents 649f2b7 + bbe8c7b commit 32ff022

999 files changed

Lines changed: 26555 additions & 12161 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.agents/rules/test-infrastructure.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,37 @@ The rule: **if production modules already wire a component, use them — don't c
8282

8383
- Prefer `using DisposableByteBuffer` via `.AsDisposable()` for releasing `IByteBuffer` in tests
8484
- For leak-detection tests, use `PooledBufferLeakDetector` from `Nethermind.Network.Test`
85+
86+
## `Assert.Multiple` — wrap independent assertions on the same fixture
87+
88+
When a test has multiple `Assert.That` calls that all examine the **same** result/state and are logically independent of each other, wrap them in `using (Assert.EnterMultipleScope()) { ... }` (the NUnit 4 form; prefer this over the older `Assert.Multiple(() => { ... })` lambda). All assertions are evaluated even if earlier ones fail, so one run surfaces every mismatch — without it, you fix the first failure only to discover the next on the following CI cycle.
89+
90+
**Before reaching for `Assert.Multiple`, dedupe first.** Multiple tests doing the same field-by-field comparison are a smell — extract a helper (`AssertX(expected, actual)`) and wrap inside the helper once. Every caller then benefits from the multi-scope automatically, and the per-field assertion messages stay intact for diagnostics.
91+
92+
```csharp
93+
// Field-by-field comparison helper — every caller benefits
94+
private static void AssertReceipt(TxReceipt expected, TxReceipt actual)
95+
{
96+
using (Assert.EnterMultipleScope())
97+
{
98+
Assert.That(actual.TxType, Is.EqualTo(expected.TxType), "tx type");
99+
Assert.That(actual.Bloom, Is.EqualTo(expected.Bloom), "bloom");
100+
Assert.That(actual.GasUsed, Is.EqualTo(expected.GasUsed), "gas used");
101+
// ...
102+
}
103+
}
104+
```
105+
106+
A custom `IEqualityComparer<T>` (or `Is.EqualTo(expected).Using(comparer)`) is the right tool when you only care **whether** two values are equal, not **which field** differs. Prefer the assertion-helper form when the failure diagnostic should name the field; prefer a comparer when "equal or not" is enough and you want a one-line callsite.
107+
108+
**Wrap when**:
109+
- N independent property/field assertions on the same object with no mutation between them
110+
- Field-by-field comparison helpers (`Compare*`, `Assert*`, `Validate*`) — wrap inside the helper so every caller benefits
111+
- Inner loop body where each iteration's assertions all check independent properties of one result — wrap **per iteration**, not around the whole loop
112+
113+
**Do NOT wrap when**:
114+
- Assertions are interleaved with state-mutating calls (`provider.Restore(...)`, `cache.Set(...)`, `list.TrySet(...)`) — a failure should stop, not run the next assert on broken state
115+
- `Assert.That(x, Is.Not.Null)` followed by `Assert.That(x.Foo, ...)` — the second NREs if the first fails; you lose information rather than gain it
116+
- Each iteration of a loop depends on the previous one's state holding the invariant
117+
118+
When an entire test method qualifies, prefer wrapping the **assertion block** at the end (after setup), not the whole body — that keeps arrange/act outside the scope where exceptions are diagnostic, not "additional failures".

.editorconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ dotnet_style_namespace_match_folder = true:warning
7575

7676
csharp_indent_labels = one_less_than_current
7777
csharp_using_directive_placement = outside_namespace:silent
78-
csharp_prefer_simple_using_statement = true:suggestion
78+
csharp_prefer_simple_using_statement = true:warning
7979
csharp_prefer_braces = when_multiline:suggestion
8080
csharp_style_namespace_declarations = file_scoped:suggestion
8181
csharp_style_prefer_method_group_conversion = true:silent

.github/workflows/build-tools.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ jobs:
3232
- StatelessInputGen/StatelessInputGen.slnx
3333
- StatsAnalyzer/StatsAnalyzer.slnx
3434
- TxParser/TxParser.slnx
35+
- RpcTests/RpcTests.slnx
3536
steps:
3637
- name: Check out repository
3738
uses: actions/checkout@v6
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
name: Deploy RPC Monitors
2+
3+
on:
4+
workflow_dispatch:
5+
6+
concurrency:
7+
group: ${{ github.workflow }}-${{ github.ref }}
8+
cancel-in-progress: true
9+
10+
jobs:
11+
build-and-push:
12+
name: Build and push Docker image
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Check out repository
16+
uses: actions/checkout@v6
17+
18+
- name: Set up .NET
19+
uses: actions/setup-dotnet@v4
20+
with:
21+
dotnet-version: '10.0.x'
22+
23+
- name: Publish
24+
run: dotnet publish tools/RpcTests/RpcTests.Monitor/RpcTests.Monitor.csproj -c Release -o publish
25+
26+
- name: Set up Docker Buildx
27+
uses: docker/setup-buildx-action@v4
28+
29+
- name: Log in to Docker Hub
30+
uses: docker/login-action@v4
31+
with:
32+
username: ${{ secrets.DOCKER_HUB_USERNAME }}
33+
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
34+
35+
- name: Build and push Docker image
36+
uses: docker/build-push-action@v6
37+
with:
38+
context: publish
39+
file: tools/RpcTests/RpcTests.Monitor/Dockerfile
40+
push: true
41+
tags: nethermindeth/rpc-monitor:latest
42+
platforms: linux/amd64
43+
44+
deploy:
45+
name: Deploy ${{ matrix.name }} monitor
46+
needs: build-and-push
47+
runs-on: ubuntu-latest
48+
strategy:
49+
matrix:
50+
include:
51+
- name: Mainnet
52+
container: rpc-monitor-mainnet
53+
target_secret: RPC_MONITOR_MAINNET_TARGET
54+
reference_url: https://ethereum-rpc.publicnode.com
55+
test_glob: mainnet/**/*
56+
- name: Gnosis
57+
container: rpc-monitor-gnosis
58+
target_secret: RPC_MONITOR_GNOSIS_TARGET
59+
reference_url: https://gnosis-rpc.publicnode.com
60+
test_glob: gnosis/**/*
61+
steps:
62+
- name: Deploy ${{ matrix.name }} monitor
63+
uses: appleboy/ssh-action@v1
64+
env:
65+
SLACK_BOT_TOKEN: ${{ secrets.RPC_MONITOR_SLACK_BOT_TOKEN }}
66+
SLACK_CHANNEL_ID: ${{ secrets.RPC_MONITOR_SLACK_CHANNEL_ID }}
67+
TARGET_URL: ${{ secrets[matrix.target_secret] }}
68+
with:
69+
host: ${{ secrets.RPC_MONITOR_SSH_HOST }}
70+
username: ${{ secrets.RPC_MONITOR_SSH_USER }}
71+
key: ${{ secrets.RPC_MONITOR_SSH_KEY }}
72+
envs: SLACK_BOT_TOKEN,SLACK_CHANNEL_ID,TARGET_URL
73+
script: |
74+
docker pull nethermindeth/rpc-monitor:latest
75+
docker stop ${{ matrix.container }} 2>/dev/null || true
76+
docker rm ${{ matrix.container }} 2>/dev/null || true
77+
docker run -d \
78+
--name ${{ matrix.container }} \
79+
--restart unless-stopped \
80+
--network host \
81+
--log-opt max-size=50m \
82+
-e RPC_MONITOR_BOT_TOKEN="$SLACK_BOT_TOKEN" \
83+
-e RPC_MONITOR_CHANNEL_ID="$SLACK_CHANNEL_ID" \
84+
nethermindeth/rpc-monitor:latest \
85+
--name "${{ matrix.name }}" \
86+
--target "$TARGET_URL" \
87+
--reference "${{ matrix.reference_url }}" \
88+
--tests "${{ matrix.test_glob }}" \
89+
--report-at "12:00:00"

.github/workflows/nethermind-tests.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ jobs:
8888
- Nethermind.Wallet.Test
8989
- Nethermind.Xdc.Test
9090
chunk: ['']
91-
exclude: # Synchronization.Test on ARM is chunked (see include block) — its unchunked variant hits the 15-min wall.
91+
exclude: # Synchronization.Test on ARM/macOS is chunked (see include block) — its unchunked variant hits the 15-min wall.
9292
- runner: ubuntu-24.04-arm
9393
project: Nethermind.Synchronization.Test
9494
chunk: ''
@@ -102,7 +102,10 @@ jobs:
102102
- { runner: macos-latest, project: Nethermind.Network.Test, chunk: '' }
103103
- { runner: macos-latest, project: Nethermind.Runner.Test, chunk: '' }
104104
- { runner: macos-latest, project: Nethermind.Sockets.Test, chunk: '' }
105-
- { runner: macos-latest, project: Nethermind.Synchronization.Test, chunk: '' }
105+
- { runner: macos-latest, project: Nethermind.Synchronization.Test, chunk: 1of4 }
106+
- { runner: macos-latest, project: Nethermind.Synchronization.Test, chunk: 2of4 }
107+
- { runner: macos-latest, project: Nethermind.Synchronization.Test, chunk: 3of4 }
108+
- { runner: macos-latest, project: Nethermind.Synchronization.Test, chunk: 4of4 }
106109
- { runner: ubuntu-24.04-arm, project: Nethermind.Synchronization.Test, chunk: 1of4 }
107110
- { runner: ubuntu-24.04-arm, project: Nethermind.Synchronization.Test, chunk: 2of4 }
108111
- { runner: ubuntu-24.04-arm, project: Nethermind.Synchronization.Test, chunk: 3of4 }

0 commit comments

Comments
 (0)