Skip to content

Commit d1825ac

Browse files
authored
Merge branch 'main' into fix/bal-selfdestruct-netzero
2 parents 41b35fb + 776e406 commit d1825ac

Some content is hidden

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

54 files changed

+2051
-531
lines changed
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
---
2+
name: erigondb-sync-integration-test-plan
3+
description: Integration test plan for erigondb.toml settings resolution across 3 runtime scenarios (legacy, fresh+downloader, fresh+no-downloader)
4+
allowed-tools: Bash, Read
5+
user-invocable: false
6+
---
7+
8+
# erigondb.toml Integration Test Plan
9+
10+
Verify that `erigondb.toml` settings are correctly resolved across three distinct runtime scenarios: legacy datadirs, fresh sync with downloader, and fresh sync without downloader.
11+
12+
Use this plan after any changes to the erigondb.toml resolution logic (creation, defaults, legacy detection, downloader delivery) to confirm all paths still work.
13+
14+
## Parameters
15+
16+
Two values must be provided by the caller:
17+
18+
| Parameter | Description | Example |
19+
|-----------|-------------|---------|
20+
| **chain** | Chain name passed to `--chain=` | `hoodi`, `mainnet` |
21+
| **legacy datadir** | Path to an existing Erigon datadir that has `preverified.toml` but **no** `erigondb.toml` | `~/eth-nodes/erigon33-hoodi-stable` |
22+
23+
All scenarios use `--prune.mode=archive`.
24+
25+
## Pre-requisites
26+
27+
1. **Built binary** — invoke `/erigon-build` if `./build/bin/erigon` does not exist.
28+
2. **Legacy datadir** — the user-provided path must contain `snapshots/preverified.toml` and must **not** contain `snapshots/erigondb.toml`.
29+
3. **Port availability** — use `/erigon-network-ports` for reference. Each scenario uses a different port offset (+100, +200, +300) via `/erigon-ephemeral` conflict detection.
30+
31+
## Scenario A: Legacy datadir
32+
33+
**Goal**: Starting on a legacy datadir (has `preverified.toml`, no `erigondb.toml`) creates `erigondb.toml` with legacy settings (`step_size = 1562500`).
34+
35+
### Steps
36+
37+
1. Create an ephemeral clone of the user's legacy datadir using `/erigon-ephemeral` (Mode B: clone). This gives an isolated copy so the original is untouched.
38+
2. Confirm pre-conditions on the clone:
39+
- `snapshots/preverified.toml` exists
40+
- `snapshots/erigondb.toml` does **not** exist
41+
3. Start erigon with port offset **+100** (via `/erigon-ephemeral` port conflict detection):
42+
```
43+
./build/bin/erigon \
44+
--datadir=<clone-path> \
45+
--chain=<chain> \
46+
--prune.mode=archive \
47+
<port flags at +100 offset>
48+
```
49+
4. Wait for startup (~15s). Check logs for a message indicating legacy settings detection (e.g., `Creating erigondb.toml with LEGACY settings`).
50+
5. Verify the generated file:
51+
```bash
52+
cat <clone-path>/snapshots/erigondb.toml
53+
```
54+
Expected: `step_size = 1562500`
55+
6. Kill the process and clean up the ephemeral datadir.
56+
57+
## Scenario B: Fresh sync with downloader
58+
59+
**Goal**: A fresh datadir (no `preverified.toml`, no `erigondb.toml`) starts with code defaults (`step_size = 1562500`), then the downloader delivers the network's `erigondb.toml` during the header-chain phase, which may have different settings (e.g., `step_size = 390625` for hoodi).
60+
61+
### Steps
62+
63+
1. Create an empty ephemeral datadir using `/erigon-ephemeral` (Mode A: empty).
64+
2. Start erigon with port offset **+200**:
65+
```
66+
./build/bin/erigon \
67+
--datadir=<empty-path> \
68+
--chain=<chain> \
69+
--prune.mode=archive \
70+
<port flags at +200 offset>
71+
```
72+
3. Check early logs for a message indicating defaults are being used (e.g., `erigondb.toml not found, using defaults`) with `step_size=1562500`.
73+
4. Wait for the header-chain download phase to complete (~30-120s depending on network). Watch logs for:
74+
- `[1/6 OtterSync] Downloader completed header-chain`
75+
- `Reading DB settings from existing erigondb.toml`
76+
- `erigondb stepSize changed, propagating` (if the network's settings differ from the code defaults)
77+
5. Verify the delivered file:
78+
```bash
79+
cat <empty-path>/snapshots/erigondb.toml
80+
```
81+
The values come from the network's published `erigondb.toml` (check the chain's webseed for the canonical values).
82+
6. Kill the process and clean up the ephemeral datadir.
83+
84+
## Scenario C: Fresh sync with `--no-downloader`
85+
86+
**Goal**: A fresh datadir with `--no-downloader` immediately writes `erigondb.toml` with code defaults (`step_size = 1562500`).
87+
88+
### Steps
89+
90+
1. Create an empty ephemeral datadir using `/erigon-ephemeral` (Mode A: empty).
91+
2. Start erigon with port offset **+300** and `--no-downloader`:
92+
```
93+
./build/bin/erigon \
94+
--datadir=<empty-path> \
95+
--chain=<chain> \
96+
--prune.mode=archive \
97+
--no-downloader \
98+
<port flags at +300 offset>
99+
```
100+
3. Check logs for a message indicating defaults were written immediately (e.g., `Initializing erigondb.toml with DEFAULT settings`) with `step_size=1562500`.
101+
4. Verify the file exists immediately:
102+
```bash
103+
cat <empty-path>/snapshots/erigondb.toml
104+
```
105+
Expected: `step_size = 1562500` (code defaults, since no downloader to provide network settings)
106+
5. Kill the process and clean up the ephemeral datadir.
107+
108+
## Success Criteria
109+
110+
| Scenario | Condition | Expected step_size | File timing |
111+
|----------|-----------|-------------------|-------------|
112+
| A (legacy) | `Creating erigondb.toml with LEGACY settings` log | 1,562,500 | Written immediately on startup |
113+
| B (fresh+downloader) | `erigondb.toml not found, using defaults` then `erigondb stepSize changed, propagating` | Code default 1,562,500 then network value (chain-dependent) | After downloader delivers it |
114+
| C (fresh+no-downloader) | `Initializing erigondb.toml with DEFAULT settings (nodownloader)` log | 1,562,500 | Written immediately on startup |
115+
116+
## Cleanup
117+
118+
After all scenarios complete, ensure all ephemeral datadirs and processes are cleaned up. Use `/erigon-ephemeral` Step 5 (cleanup) for each instance, or Step 6 (leftover detection) to find any stragglers.

.github/workflows/scripts/run_rpc_tests_ethereum.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,4 @@ DISABLED_TEST_LIST=(
4141
DISABLED_TESTS=$(IFS=,; echo "${DISABLED_TEST_LIST[*]}")
4242

4343
# Call the main test runner script with the required and optional parameters
44-
"$(dirname "$0")/run_rpc_tests.sh" mainnet v1.120.0 "$DISABLED_TESTS" "$WORKSPACE" "$RESULT_DIR"
44+
"$(dirname "$0")/run_rpc_tests.sh" mainnet v1.121.0 "$DISABLED_TESTS" "$WORKSPACE" "$RESULT_DIR"

.github/workflows/scripts/run_rpc_tests_ethereum_latest.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,4 @@ DISABLED_TEST_LIST=(
3434
DISABLED_TESTS=$(IFS=,; echo "${DISABLED_TEST_LIST[*]}")
3535

3636
# Call the main test runner script with the required and optional parameters
37-
"$(dirname "$0")/run_rpc_tests.sh" mainnet v1.120.0 "$DISABLED_TESTS" "$WORKSPACE" "$RESULT_DIR" "latest" "$REFERENCE_HOST" "do-not-compare-error-message" "$DUMP_RESPONSE"
37+
"$(dirname "$0")/run_rpc_tests.sh" mainnet v1.121.0 "$DISABLED_TESTS" "$WORKSPACE" "$RESULT_DIR" "latest" "$REFERENCE_HOST" "do-not-compare-error-message" "$DUMP_RESPONSE"

.github/workflows/scripts/run_rpc_tests_gnosis.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,5 @@ DISABLED_TEST_LIST=(
2222
DISABLED_TESTS=$(IFS=,; echo "${DISABLED_TEST_LIST[*]}")
2323

2424
# Call the main test runner script with the required and optional parameters
25-
"$(dirname "$0")/run_rpc_tests.sh" gnosis v1.120.0 "$DISABLED_TESTS" "$WORKSPACE" "$RESULT_DIR"
25+
"$(dirname "$0")/run_rpc_tests.sh" gnosis v1.121.0 "$DISABLED_TESTS" "$WORKSPACE" "$RESULT_DIR"
2626

.github/workflows/scripts/run_rpc_tests_remote_ethereum.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,4 @@ DISABLED_TEST_LIST=(
2828
DISABLED_TESTS=$(IFS=,; echo "${DISABLED_TEST_LIST[*]}")
2929

3030
# Call the main test runner script with the required and optional parameters
31-
"$(dirname "$0")/run_rpc_tests.sh" mainnet v1.120.0 "$DISABLED_TESTS" "$WORKSPACE" "$RESULT_DIR"
31+
"$(dirname "$0")/run_rpc_tests.sh" mainnet v1.121.0 "$DISABLED_TESTS" "$WORKSPACE" "$RESULT_DIR"

.github/workflows/test-all-erigon.yml

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ jobs:
119119
concurrency:
120120
group: >-
121121
${{
122-
(github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')) &&
122+
(github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')) &&
123123
format('{0}-{1}-{2}', github.workflow, matrix.os, github.run_id) ||
124124
format('{0}-{1}-{2}', github.workflow, matrix.os, github.ref)
125125
}}
@@ -130,6 +130,10 @@ jobs:
130130
runs-on:
131131
group: "selfhosted-win"
132132

133+
env:
134+
GOMODCACHE: C:\go-cache\mod
135+
GOCACHE: C:\go-cache\build
136+
133137
steps:
134138
# not needed on self-hosted runner. already configured.
135139
#- name: Configure Pagefile
@@ -147,6 +151,12 @@ jobs:
147151
lfs: true
148152
clean: true
149153

154+
# Prune LFS blobs that are no longer referenced by the current checkout.
155+
- name: Prune stale Git LFS objects
156+
if: needs.source-of-changes.outputs.changed_files != 'true'
157+
shell: bash
158+
run: git lfs prune --verify-remote=false
159+
150160
- name: Setup Go environment on ${{ matrix.os }}
151161
if: needs.source-of-changes.outputs.changed_files != 'true'
152162
uses: actions/setup-go@v6
@@ -161,15 +171,20 @@ jobs:
161171
- name: Run all tests on ${{ matrix.os }}
162172
if: needs.source-of-changes.outputs.changed_files != 'true'
163173
shell: bash
164-
env:
165-
GOMODCACHE: C:\go-cache\mod
166-
GOCACHE: C:\go-cache\build
167174
run: make test-all
168175

169-
- name: Cleanup
176+
# Clears the Go build cache after the run so compiled artifacts do not
177+
# accumulate on the persistent self-hosted runner across runs.
178+
# GOMODCACHE is intentionally kept: it is bounded by the number of unique
179+
# dependency versions and saves re-downloading modules on the next run.
180+
- name: Post-run cleanup
170181
if: always()
182+
shell: bash
171183
run: |
172-
Remove-Item -Path "$env:TEMP\*" -Recurse -Force -ErrorAction SilentlyContinue
184+
go clean -cache
185+
rm -f coverage-test-all.out
186+
rm -rf "$TEMP/"* 2>/dev/null || true
187+
rm -rf "$RUNNER_TEMP/"* 2>/dev/null || true
173188
174189
- name: This ${{ matrix.os }} check does not make sense for changes within out-of-scope directories
175190
if: needs.source-of-changes.outputs.changed_files == 'true'

cl/p2p/p2p_localnode.go

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,44 @@ func newLocalNode(
2626
}
2727
localNode := enode.NewLocalNode(db, privKey)
2828

29-
ipEntry := enr.IP(ipAddr)
3029
udpEntry := enr.UDP(udpPort)
3130
tcpEntry := enr.TCP(tcpPort)
3231

33-
localNode.Set(ipEntry)
3432
localNode.Set(udpEntry)
3533
localNode.Set(tcpEntry)
36-
37-
localNode.SetFallbackIP(ipAddr)
3834
localNode.SetFallbackUDP(udpPort)
3935

36+
if ipAddr.IsUnspecified() {
37+
if detected := detectOutboundIP(ipAddr); detected != nil {
38+
logger.Info("[Caplin] Discovery address is unspecified, using detected outbound IP for ENR. Set --caplin.discovery.addr explicitly to override", "detected", detected)
39+
ipAddr = detected
40+
} else {
41+
logger.Warn("[Caplin] Discovery address is unspecified and outbound IP detection failed, ENR will have no IP. Set --caplin.discovery.addr to your public IP")
42+
}
43+
}
44+
if !ipAddr.IsUnspecified() {
45+
localNode.Set(enr.IP(ipAddr))
46+
localNode.SetFallbackIP(ipAddr)
47+
}
48+
4049
return localNode, nil
4150
}
4251

52+
// detectOutboundIP determines the preferred outbound IP address by asking the
53+
// OS routing table (no actual traffic is sent). Returns nil if detection fails.
54+
func detectOutboundIP(unspecified net.IP) net.IP {
55+
network, target := "udp4", "8.8.8.8:80"
56+
if unspecified.To4() == nil {
57+
network, target = "udp6", "[2001:4860:4860::8888]:80"
58+
}
59+
conn, err := net.Dial(network, target)
60+
if err != nil {
61+
return nil
62+
}
63+
defer conn.Close()
64+
return conn.LocalAddr().(*net.UDPAddr).IP
65+
}
66+
4367
func NewUDPv5Listener(ctx context.Context, cfg *P2PConfig, discCfg discover.Config, logger log.Logger) (*discover.UDPv5, error) {
4468
var (
4569
ipAddr = cfg.IpAddr

cl/sentinel/sentinel.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -274,21 +274,22 @@ func (s *Sentinel) Identity() (pid, enrStr string, p2pAddresses, discoveryAddres
274274
}
275275
discoveryAddresses = []string{}
276276

277-
if s.listener.LocalNode().Node().TCP() != 0 {
277+
nodeIP := s.listener.LocalNode().Node().IP()
278+
if nodeIP == nil {
279+
s.logger.Warn("[Sentinel] Discovery node has nil IP address, skipping discovery address advertisement. Check caplin.discovery.addr configuration and host IPv6 setup")
280+
} else {
278281
protocol := "ip4"
279-
if s.listener.LocalNode().Node().IP().To4() == nil {
282+
if nodeIP.To4() == nil {
280283
protocol = "ip6"
281284
}
282-
port := s.listener.LocalNode().Node().TCP()
283-
discoveryAddresses = append(discoveryAddresses, fmt.Sprintf("/%s/%s/tcp/%d/p2p/%s", protocol, s.listener.LocalNode().Node().IP(), port, pid))
284-
}
285-
if s.listener.LocalNode().Node().UDP() != 0 {
286-
protocol := "ip4"
287-
if s.listener.LocalNode().Node().IP().To4() == nil {
288-
protocol = "ip6"
285+
if s.listener.LocalNode().Node().TCP() != 0 {
286+
port := s.listener.LocalNode().Node().TCP()
287+
discoveryAddresses = append(discoveryAddresses, fmt.Sprintf("/%s/%s/tcp/%d/p2p/%s", protocol, nodeIP, port, pid))
288+
}
289+
if s.listener.LocalNode().Node().UDP() != 0 {
290+
port := s.listener.LocalNode().Node().UDP()
291+
discoveryAddresses = append(discoveryAddresses, fmt.Sprintf("/%s/%s/udp/%d/p2p/%s", protocol, nodeIP, port, pid))
289292
}
290-
port := s.listener.LocalNode().Node().UDP()
291-
discoveryAddresses = append(discoveryAddresses, fmt.Sprintf("/%s/%s/udp/%d/p2p/%s", protocol, s.listener.LocalNode().Node().IP(), port, pid))
292293
}
293294
subnetField := bitfield.NewBitvector64()
294295
syncnetField := bitfield.NewBitvector8()

cmd/integration/commands/stages.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1133,7 +1133,11 @@ func allSnapshots(ctx context.Context, db kv.RoDB, logger log.Logger) (*freezebl
11331133
blockReader := freezeblocks.NewBlockReader(_allSnapshotsSingleton, _allBorSnapshotsSingleton)
11341134
txNums := blockReader.TxnumReader()
11351135

1136-
_aggSingleton = dbstate.New(dirs).Logger(logger).MustOpen(ctx, db)
1136+
var erigonDBSettings *dbstate.ErigonDBSettings
1137+
if erigonDBSettings, err = dbstate.ResolveErigonDBSettings(dirs, logger, false); err != nil {
1138+
return
1139+
}
1140+
_aggSingleton = dbstate.New(dirs).Logger(logger).WithErigonDBSettings(erigonDBSettings).MustOpen(ctx, db)
11371141

11381142
_aggSingleton.SetProduceMod(snapCfg.ProduceE3)
11391143

cmd/mcp/README.md

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -118,41 +118,46 @@ for datadir mode.
118118
## Available Tools
119119

120120
### Ethereum Standard (eth_*)
121+
121122
`eth_blockNumber`, `eth_getBlockByNumber`, `eth_getBlockByHash`,
122123
`eth_getBalance`, `eth_getTransactionByHash`, `eth_getTransactionReceipt`,
123124
`eth_getBlockReceipts`, `eth_getLogs`, `eth_getCode`, `eth_getStorageAt`,
124125
`eth_getTransactionCount`, `eth_call`, `eth_estimateGas`, `eth_gasPrice`,
125126
`eth_chainId`, `eth_syncing`, `eth_getProof`, and more.
126127

127128
### Erigon-Specific (erigon_*)
129+
128130
`erigon_forks`, `erigon_blockNumber`, `erigon_getHeaderByNumber`,
129131
`erigon_getHeaderByHash`, `erigon_getBlockByTimestamp`,
130132
`erigon_getBalanceChangesInBlock`, `erigon_getLogsByHash`,
131133
`erigon_getLogs`, `erigon_getBlockReceiptsByBlockHash`, `erigon_nodeInfo`.
132134

133135
### Otterscan (ots_*)
136+
134137
`ots_getApiLevel`, `ots_getInternalOperations`,
135138
`ots_searchTransactionsBefore`, `ots_searchTransactionsAfter`,
136139
`ots_getBlockDetails`, `ots_getBlockTransactions`, `ots_hasCode`,
137140
`ots_traceTransaction`, `ots_getTransactionError`,
138141
`ots_getTransactionBySenderAndNonce`, `ots_getContractCreator`.
139142

140143
### Log Analysis
144+
141145
`logs_tail`, `logs_head`, `logs_grep`, `logs_stats` — requires `--log.dir`
142146
or `--datadir` to locate Erigon/torrent log files.
143147

144148
### Metrics
149+
145150
`metrics_list`, `metrics_get` — only available in embedded mode (inside Erigon).
146151
In standalone mode, these return an informational message.
147152

148153
## Flags
149154

150-
| Flag | Default | Description |
151-
|------|---------|-------------|
152-
| `--rpc.url` | `http://127.0.0.1:8545` | Erigon JSON-RPC endpoint URL |
153-
| `--port` | 0 | JSON-RPC port shorthand |
154-
| `--datadir` | | Erigon data directory (enables direct DB mode) |
155-
| `--private.api.addr` | `127.0.0.1:9090` | gRPC private API (with --datadir) |
156-
| `--transport` | `stdio` | Transport: `stdio` or `sse` |
157-
| `--sse.addr` | `127.0.0.1:8553` | SSE listen address |
158-
| `--log.dir` | | Log directory (overrides datadir detection) |
155+
| Flag | Default | Description |
156+
|----------------------|-------------------------|------------------------------------------------|
157+
| `--rpc.url` | `http://127.0.0.1:8545` | Erigon JSON-RPC endpoint URL |
158+
| `--port` | 0 | JSON-RPC port shorthand |
159+
| `--datadir` | | Erigon data directory (enables direct DB mode) |
160+
| `--private.api.addr` | `127.0.0.1:9090` | gRPC private API (with --datadir) |
161+
| `--transport` | `stdio` | Transport: `stdio` or `sse` |
162+
| `--sse.addr` | `127.0.0.1:8553` | SSE listen address |
163+
| `--log.dir` | | Log directory (overrides datadir detection) |

0 commit comments

Comments
 (0)