@blinklabs/dingo 0.36.1 → 0.38.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +33 -97
- package/CLAUDE.md +19 -15
- package/RELEASE_NOTES.md +75 -0
- package/dingo.yaml.example +63 -0
- package/docs/dashboards/README.md +188 -0
- package/docs/dashboards/alerts.yaml +29 -0
- package/docs/dashboards/prometheus.yaml +16 -0
- package/docs/dashboards/provisioning.yaml +14 -0
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -1,115 +1,51 @@
|
|
|
1
1
|
# AGENTS.md
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Go Cardano node (Ouroboros). See `CLAUDE.md` for detailed rules; this file has additional content (Build/test section, `make golines` in pre-commit, Key events table) and a different structure — the two are related but not exact copies. Package layout, targets, and flags are derivable from `Makefile`, `go.mod`, `node.go`.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Build / test
|
|
6
6
|
|
|
7
|
-
**Dingo**: Go-based Cardano blockchain node by Blink Labs (Ouroboros protocol, UTxO tracking, pluggable storage).
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
make # Format, test, build
|
|
11
|
-
make test # Tests with race detection
|
|
12
|
-
make bench # Run benchmarks
|
|
13
|
-
go run ./cmd/dingo/ # Run without building
|
|
14
|
-
go test -v -race -run TestName ./path/to/package/ # Single test
|
|
15
7
|
```
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
| Package | Purpose |
|
|
20
|
-
|---------|---------|
|
|
21
|
-
| `chain/` | Blockchain state, fork detection, rollback |
|
|
22
|
-
| `chainselection/` | Multi-peer chain comparison (Ouroboros Praos) |
|
|
23
|
-
| `chainsync/` | Block sync state tracking |
|
|
24
|
-
| `connmanager/` | Network connection lifecycle |
|
|
25
|
-
| `database/` | Storage plugins (badger, sqlite, postgres, mysql, gcs, s3) |
|
|
26
|
-
| `event/` | Event bus (async pub/sub, 4 workers) |
|
|
27
|
-
| `ledger/` | UTxO state, protocol params, Plutus execution |
|
|
28
|
-
| `mempool/` | Transaction pool & validation |
|
|
29
|
-
| `ouroboros/` | Protocol handlers (N2N, N2C) |
|
|
30
|
-
| `peergov/` | Peer governance, churn, quotas |
|
|
31
|
-
| `utxorpc/` | UTxO RPC gRPC server |
|
|
32
|
-
|
|
33
|
-
## Code Quality (Run Before Committing)
|
|
34
|
-
|
|
35
|
-
```bash
|
|
36
|
-
golangci-lint run ./... # Linters (39 via .golangci.yml)
|
|
37
|
-
nilaway ./... # Nil-safety analyzer
|
|
38
|
-
modernize ./... # Modern Go idioms
|
|
39
|
-
make golines # 80 char line limit
|
|
8
|
+
make # fmt, test, build
|
|
9
|
+
make test # tests with -race
|
|
10
|
+
go test -v -race -run TestName ./path/to/pkg/
|
|
40
11
|
```
|
|
41
12
|
|
|
42
|
-
##
|
|
43
|
-
|
|
44
|
-
### Error Handling
|
|
45
|
-
```go
|
|
46
|
-
// Wrap errors with context
|
|
47
|
-
return fmt.Errorf("failed to process block: %w", err)
|
|
48
|
-
```
|
|
13
|
+
## Pre-commit
|
|
49
14
|
|
|
50
|
-
### Event-Driven Communication
|
|
51
|
-
```go
|
|
52
|
-
// Subscribe to events (never call components directly)
|
|
53
|
-
eventBus.SubscribeFunc(chain.ChainForkEventType, handler)
|
|
54
15
|
```
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
db.Where("id IN ?", ids).Find(&records)
|
|
60
|
-
|
|
61
|
-
// BAD: N+1 queries
|
|
62
|
-
for _, id := range ids {
|
|
63
|
-
db.Where("id = ?", id).First(&record)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Certificate ordering: use cert_index as tie-breaker
|
|
67
|
-
Order("added_slot DESC, cert_index DESC")
|
|
16
|
+
golangci-lint run ./...
|
|
17
|
+
nilaway ./...
|
|
18
|
+
modernize ./...
|
|
19
|
+
make golines
|
|
68
20
|
```
|
|
69
21
|
|
|
70
|
-
|
|
71
|
-
- `Chain.Rollback(point)` emits `ChainRollbackEvent`
|
|
72
|
-
- State restoration in `database/plugin/metadata/sqlite/`
|
|
73
|
-
- Use `TransactionEvent.Rollback` field to detect undo operations
|
|
74
|
-
|
|
75
|
-
### CBOR Storage
|
|
76
|
-
- UTxOs/TXs stored as 52-byte `CborOffset` (magic "DOFF" + slot + hash + offset + length)
|
|
77
|
-
- `TieredCborCache` resolves: hot cache → block LRU → cold extraction
|
|
78
|
-
|
|
79
|
-
### Stake Snapshots
|
|
80
|
-
- Mark/Set/Go rotation at epoch boundaries (Ouroboros Praos)
|
|
81
|
-
- `LedgerView.GetStakeDistribution(epoch)` for leader election queries
|
|
82
|
-
- `PoolStakeSnapshot` model stores per-pool stake
|
|
83
|
-
- `EpochSummary` stores network aggregates
|
|
84
|
-
|
|
85
|
-
## Key Event Types
|
|
86
|
-
|
|
87
|
-
| Event | Purpose |
|
|
88
|
-
|-------|---------|
|
|
89
|
-
| `chain.update` | Block added to chain |
|
|
90
|
-
| `chain.fork-detected` | Fork detected |
|
|
91
|
-
| `chainselection.chain_switch` | Active peer changed |
|
|
92
|
-
| `epoch.transition` | Epoch boundary crossed (triggers stake snapshot) |
|
|
93
|
-
| `mempool.add_tx` / `mempool.remove_tx` | Transaction lifecycle |
|
|
94
|
-
| `connmanager.conn-closed` | Connection lifecycle |
|
|
95
|
-
| `peergov.peer-churn` | Peer rotation |
|
|
22
|
+
## Testing rules
|
|
96
23
|
|
|
97
|
-
|
|
24
|
+
- No `time.Sleep()` for sync — use `internal/test/testutil/` (`WaitForCondition`, `RequireReceive`, `context.WithTimeout`).
|
|
25
|
+
- Integration tests: `internal/integration/` + `database/immutable/testdata/` (real blocks, slots 0–1.3M).
|
|
26
|
+
- Mock fixtures come from `github.com/blinklabs-io/ouroboros-mock` (`fixtures/`, `ledger/`, `conformance/`). Never duplicate mocks inside dingo — extend the shared library so every Blink Labs app (dingo, gouroboros, adder, ...) reuses the same test surface.
|
|
98
27
|
|
|
99
|
-
|
|
28
|
+
## Non-obvious invariants
|
|
100
29
|
|
|
101
|
-
|
|
30
|
+
- EventBus for async cross-component notifications: use `event.EventBus.SubscribeFunc()` for block/chain/mempool/peer events. Synchronous state queries between components still use direct method calls.
|
|
31
|
+
- CBOR offsets: UTxOs/txs stored as 52-byte refs (magic `"DOFF"` + slot + hash + offset + length), resolved by `TieredCborCache` (hot → block LRU → cold extract). See `database/cbor_offset.go`.
|
|
32
|
+
- Cert ordering: `Order("added_slot DESC, block_index DESC, cert_index DESC")` — `cert_index` resets per tx, so `block_index` is required to disambiguate across txs in the same block.
|
|
33
|
+
- Rollbacks: delivered on `chain.update` as a `chain.ChainRollbackEvent` payload (no separate `chain.rollback` topic); also subscribe to `chain.fork_detected` for fork metrics. Check `TransactionEvent.Rollback` for undo.
|
|
34
|
+
- Stake snapshots: mark/set/go rotation at epoch boundaries (Praos). `LedgerView.GetStakeDistribution(epoch)` for leader election. Per-pool stake in `PoolStakeSnapshot`; aggregates in `EpochSummary`.
|
|
35
|
+
- Plugins (`database/plugin/`): blob = `badger` | `gcs` | `s3`; metadata = `sqlite` | `mysql` | `postgres`.
|
|
102
36
|
|
|
103
|
-
##
|
|
37
|
+
## Key events
|
|
104
38
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
39
|
+
| Event | Meaning |
|
|
40
|
+
|---|---|
|
|
41
|
+
| `chain.update` | block added |
|
|
42
|
+
| `chain.fork_detected` | fork |
|
|
43
|
+
| `chainselection.chain_switch` | active peer changed |
|
|
44
|
+
| `epoch.transition` | epoch boundary — triggers stake snapshot |
|
|
45
|
+
| `mempool.add_tx` / `mempool.remove_tx` | tx lifecycle |
|
|
46
|
+
| `connmanager.conn_closed` | connection closed |
|
|
47
|
+
| `peergov.peer_churn` | peer rotation |
|
|
110
48
|
|
|
111
|
-
##
|
|
49
|
+
## Config
|
|
112
50
|
|
|
113
|
-
|
|
114
|
-
- Test data: `database/immutable/testdata/` (real blocks slots 0-1.3M)
|
|
115
|
-
- Benchmarks: `make bench` (28+ benchmarks)
|
|
51
|
+
Priority: CLI > env > YAML > defaults. Key env vars: `CARDANO_NETWORK`, `CARDANO_DATABASE_PATH`, `DINGO_DATABASE_BLOB_PLUGIN`, `DINGO_DATABASE_METADATA_PLUGIN`.
|
package/CLAUDE.md
CHANGED
|
@@ -1,33 +1,37 @@
|
|
|
1
1
|
# CLAUDE.md
|
|
2
2
|
|
|
3
|
-
Go
|
|
3
|
+
Go Cardano node (Ouroboros). Derivable info (build targets, flags, package layout) lives in `Makefile`, `go.mod`, `node.go`, `dingo.yaml.example`. This file is only what isn't derivable.
|
|
4
4
|
|
|
5
|
-
## Testing
|
|
5
|
+
## Testing
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
- `WaitForCondition` / `require.Eventually`
|
|
7
|
+
- No `time.Sleep()` for sync. Use `internal/test/testutil/`:
|
|
8
|
+
- `WaitForCondition` / `require.Eventually` — 2–5s timeout, 5–10ms interval, lock shared state inside the condition fn
|
|
9
9
|
- `RequireReceive` / `RequireNoReceive` for channel assertions
|
|
10
|
-
- `context.WithTimeout` for graceful shutdown
|
|
11
|
-
-
|
|
10
|
+
- `context.WithTimeout` for graceful shutdown
|
|
11
|
+
- `make test` runs with `-race`.
|
|
12
12
|
- Integration tests in `internal/integration/` load real blocks from `database/immutable/testdata/`.
|
|
13
|
+
- Mock fixtures come from `github.com/blinklabs-io/ouroboros-mock` (`fixtures/`, `ledger/`, `conformance/`). Never add local ledger/consensus/network mocks — extend the shared library.
|
|
13
14
|
|
|
14
|
-
##
|
|
15
|
+
## Pre-commit
|
|
15
16
|
|
|
16
|
-
```
|
|
17
|
-
golangci-lint run ./...
|
|
17
|
+
```shell
|
|
18
|
+
golangci-lint run ./...
|
|
18
19
|
nilaway ./...
|
|
19
|
-
modernize ./...
|
|
20
|
+
modernize ./... # --fix to auto-apply
|
|
20
21
|
```
|
|
21
22
|
|
|
22
|
-
## Non-obvious
|
|
23
|
+
## Non-obvious invariants
|
|
23
24
|
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
25
|
+
- CBOR offsets: UTxOs/txs store 52-byte `CborOffset` refs (magic `"DOFF"` + slot + hash + offset + length), not full CBOR. Resolved via `TieredCborCache` (hot → block LRU → cold blob extract). See `database/cbor_offset.go`, `database/cbor_cache.go`, `database/block_indexer.go`.
|
|
26
|
+
- EventBus for async cross-component notifications: block/chain/mempool/peer events go through `event.EventBus.SubscribeFunc()`. Synchronous state queries between components still use direct method calls.
|
|
27
|
+
- Cert ordering: multiple certs per slot — tie-break with `Order("added_slot DESC, block_index DESC, cert_index DESC")` (`cert_index` resets per tx, so `block_index` is required to disambiguate across txs in the same block).
|
|
28
|
+
- Rollbacks: `Chain.Rollback(point)` emits `ChainRollbackEvent`; check `TransactionEvent.Rollback` for undo.
|
|
29
|
+
- Plugins (`database/plugin/`): blob = `badger` (default) | `gcs` | `s3`; metadata = `sqlite` (default) | `mysql` | `postgres`.
|
|
30
|
+
- Config priority: CLI > env > YAML > defaults.
|
|
27
31
|
|
|
28
32
|
## Profiling
|
|
29
33
|
|
|
30
|
-
```
|
|
34
|
+
```shell
|
|
31
35
|
./dingo --cpuprofile=cpu.prof --memprofile=mem.prof load database/immutable/testdata
|
|
32
36
|
go tool pprof cpu.prof
|
|
33
37
|
```
|
package/RELEASE_NOTES.md
CHANGED
|
@@ -1,6 +1,81 @@
|
|
|
1
1
|
# Release Notes
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
## v0.37.0 (April 27, 2026)
|
|
5
|
+
|
|
6
|
+
**Title:** Genesis bootstrap, governance, and steadier Mithril recovery
|
|
7
|
+
|
|
8
|
+
**Date:** April 27, 2026
|
|
9
|
+
|
|
10
|
+
**Version:** v0.37.0
|
|
11
|
+
|
|
12
|
+
Hi folks! Here’s what we shipped in v0.37.0.
|
|
13
|
+
|
|
14
|
+
### ✨ What's New
|
|
15
|
+
|
|
16
|
+
* Added **Ouroboros Genesis bootstrap support:** Operators can now start from Genesis bootstrap flows, which gives early sync a clearer path before the node reaches the current chain tip.
|
|
17
|
+
* Expanded **Genesis mode chain selection:** Nodes can now choose the chain more safely during Genesis mode, which keeps early sync aligned with the right history.
|
|
18
|
+
* Introduced **bootstrap aware peer promotion:** Peer promotion now accounts for bootstrap state, which helps early sync keep useful peers active while the node is still catching up.
|
|
19
|
+
* Delivered **Conway governance ratification support:** Governance aware services can now track ratified actions more completely as Conway governance advances.
|
|
20
|
+
* Enabled **Conway governance enactment handling:** Governance state now follows enacted actions more accurately, which gives operators and integrators a clearer view of active governance outcomes.
|
|
21
|
+
* Preserved **committee quorum persistence:** Committee quorum information now persists across restarts, which keeps governance state steadier after interruptions.
|
|
22
|
+
* Opened **broader governance state handling:** Governance aware integrations can now read and handle more of the Conway governance state without losing important context.
|
|
23
|
+
* Unlocked **new Blockfrost compatible block endpoints:** Blockfrost compatible users can now retrieve additional block details through new block endpoints.
|
|
24
|
+
* Extended **new Blockfrost compatible network endpoints:** Network status integrations can now access new network endpoints in a Blockfrost compatible shape.
|
|
25
|
+
* Introduced **new Blockfrost compatible era endpoints:** Era aware clients can now request era information through new Blockfrost compatible endpoints.
|
|
26
|
+
* Added **new Blockfrost compatible genesis endpoints:** Genesis data is now available through new Blockfrost compatible endpoints for services that need network bootstrap details.
|
|
27
|
+
|
|
28
|
+
### 💪 Improvements
|
|
29
|
+
|
|
30
|
+
* Improved **newer Mithril snapshot compatibility:** Bootstrap runs now accept newer snapshot shapes more reliably, which makes setup and recovery smoother across current Mithril data.
|
|
31
|
+
* Refined **interrupted Mithril resume safety:** Resuming after an interrupted Mithril run now behaves more safely, which reduces the chance of a broken recovery path.
|
|
32
|
+
* Enhanced **bootstrap aware peer governance:** Peer promotion and selection now align more closely with bootstrap state, which helps early sync keep useful peers active.
|
|
33
|
+
* Modernized **bootstrap and governance observability:** Operators can now see more metrics and event signals around bootstrap and governance behavior.
|
|
34
|
+
* Updated **operator and integrator guidance:** Documentation and workflow refreshes make recent bootstrap, governance, and API behavior easier to follow.
|
|
35
|
+
|
|
36
|
+
### 🔧 Fixes
|
|
37
|
+
|
|
38
|
+
* Fixed **Mithril bootstrap resume reliability:** Mithril bootstrap and resume handling now recover more reliably when a previous run stopped before completion.
|
|
39
|
+
* Corrected **snapshot bootstrap handling:** Snapshot based bootstrap flows now handle current snapshot layouts correctly, which reduces failed setup paths.
|
|
40
|
+
* Hardened **early sync recovery behavior:** Recovery during early sync now follows Genesis mode chain selection and bootstrap aware promotion more safely after interruptions.
|
|
41
|
+
* Stabilized **governance state continuity:** Governance state now keeps ratification, enactment, and committee quorum handling steadier across restarts and replay.
|
|
42
|
+
|
|
43
|
+
### 📋 What You Need to Know
|
|
44
|
+
|
|
45
|
+
* Clarified **Genesis bootstrap rollout:** Ouroboros Genesis bootstrap changes early sync behavior, including Genesis mode chain selection and bootstrap aware peer promotion.
|
|
46
|
+
* Highlighted **governance support growth:** Conway governance coverage now reaches ratification, enactment, committee quorum persistence, and broader governance state handling.
|
|
47
|
+
* Emphasized **steadier Mithril recovery:** Mithril bootstrap and resume handling now work more reliably with newer snapshot shapes and safer interrupted resume behavior.
|
|
48
|
+
* Summarized **expanded Blockfrost compatibility:** Blockfrost compatible users can now use new block, network, era, and genesis endpoints.
|
|
49
|
+
|
|
50
|
+
### 🙏 Thank You
|
|
51
|
+
|
|
52
|
+
Thank you for trying!
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## v0.36.1 (April 21, 2026)
|
|
57
|
+
|
|
58
|
+
**Title:** Steadier catch-up sync and refreshed integrations
|
|
59
|
+
|
|
60
|
+
**Date:** April 21, 2026
|
|
61
|
+
|
|
62
|
+
**Version:** v0.36.1
|
|
63
|
+
|
|
64
|
+
Hi folks! Here’s what we shipped in v0.36.1.
|
|
65
|
+
|
|
66
|
+
### 💪 Improvements
|
|
67
|
+
|
|
68
|
+
* Improved **catch-up sync stability:** Nodes now stay steadier while catching up because stall checks wait longer, plateau recovery allows more time, and recycle cooldowns stay longer until the node reaches tip, which reduces unnecessary connection recycling and socket churn during large syncs.
|
|
69
|
+
* Updated **AWS integration currency:** AWS backed integrations stay current because the AWS SDK config package and related AWS modules were refreshed.
|
|
70
|
+
* Refreshed **core AWS compatibility:** AWS integrated behavior stays aligned with upstream fixes because the core AWS SDK and `aws/smithy-go` were updated.
|
|
71
|
+
* Modernized **Google API client support:** Google API client support stays current because `google.golang.org/api` now uses a newer release.
|
|
72
|
+
|
|
73
|
+
### 🙏 Thank You
|
|
74
|
+
|
|
75
|
+
Thank you for trying!
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
4
79
|
## v0.36.0 (April 20, 2026)
|
|
5
80
|
|
|
6
81
|
**Title:** Asset endpoints and steadier chain operations
|
package/dingo.yaml.example
CHANGED
|
@@ -4,11 +4,13 @@
|
|
|
4
4
|
# runtime default.
|
|
5
5
|
|
|
6
6
|
# Public bind address for the Dingo server
|
|
7
|
+
# CLI: --bind-addr
|
|
7
8
|
bindAddr: "0.0.0.0"
|
|
8
9
|
|
|
9
10
|
# Path to the Cardano node configuration file
|
|
10
11
|
#
|
|
11
12
|
# Can be overridden with the config environment variable
|
|
13
|
+
# CLI: --cardano-config
|
|
12
14
|
cardanoConfig: "./config/cardano/preview/config.json"
|
|
13
15
|
|
|
14
16
|
# Global data directory for both blob and metadata storage plugins.
|
|
@@ -110,9 +112,11 @@ database:
|
|
|
110
112
|
dsn: ""
|
|
111
113
|
|
|
112
114
|
# Path to the UNIX domain socket file used by the server
|
|
115
|
+
# CLI: --socket-path
|
|
113
116
|
socketPath: "dingo.socket"
|
|
114
117
|
|
|
115
118
|
# Name of the Cardano network
|
|
119
|
+
# CLI: --network
|
|
116
120
|
network: "preview"
|
|
117
121
|
|
|
118
122
|
# TLS certificate file path (for HTTPS)
|
|
@@ -129,17 +133,20 @@ tlsKeyFilePath: ""
|
|
|
129
133
|
topology: ""
|
|
130
134
|
|
|
131
135
|
# TCP port to bind for Prometheus metrics endpoint
|
|
136
|
+
# CLI: --metrics-port
|
|
132
137
|
metricsPort: 12798
|
|
133
138
|
|
|
134
139
|
# Internal/private address to bind for listening for Ouroboros NtC
|
|
135
140
|
privateBindAddr: "127.0.0.1"
|
|
136
141
|
|
|
137
142
|
# TCP port to bind for listening for Ouroboros NtC
|
|
143
|
+
# CLI: --private-port
|
|
138
144
|
privatePort: 3002
|
|
139
145
|
|
|
140
146
|
# TCP port to bind for listening for Ouroboros NtN
|
|
141
147
|
#
|
|
142
148
|
# Can be overridden with the port environment variable
|
|
149
|
+
# CLI: --port
|
|
143
150
|
relayPort: 3001
|
|
144
151
|
|
|
145
152
|
# Storage mode controls how much data is persisted.
|
|
@@ -149,6 +156,7 @@ relayPort: 3001
|
|
|
149
156
|
# redeemers). All APIs start automatically on their default ports.
|
|
150
157
|
#
|
|
151
158
|
# Can be overridden with DINGO_STORAGE_MODE
|
|
159
|
+
# CLI: --storage-mode
|
|
152
160
|
storageMode: "core"
|
|
153
161
|
|
|
154
162
|
# API ports — only used when storageMode is "api".
|
|
@@ -157,15 +165,19 @@ storageMode: "core"
|
|
|
157
165
|
#
|
|
158
166
|
# UTxO RPC gRPC API port (default: 9090)
|
|
159
167
|
# Can be overridden with DINGO_UTXORPC_PORT
|
|
168
|
+
# CLI: --utxorpc-port
|
|
160
169
|
utxorpcPort: 9090
|
|
161
170
|
# Blockfrost-compatible REST API port (default: 3000)
|
|
162
171
|
# Can be overridden with DINGO_BLOCKFROST_PORT
|
|
172
|
+
# CLI: --blockfrost-port
|
|
163
173
|
blockfrostPort: 3000
|
|
164
174
|
# Mesh (Coinbase Rosetta) REST API port (default: 8080)
|
|
165
175
|
# Can be overridden with DINGO_MESH_PORT
|
|
176
|
+
# CLI: --mesh-port
|
|
166
177
|
meshPort: 8080
|
|
167
178
|
|
|
168
179
|
# base url of bark archive server
|
|
180
|
+
# CLI: --bark-url
|
|
169
181
|
barkBaseUrl: ""
|
|
170
182
|
|
|
171
183
|
# number of slots from tip within which blocks
|
|
@@ -173,6 +185,7 @@ barkBaseUrl: ""
|
|
|
173
185
|
barkSecurityWindow: 10000
|
|
174
186
|
|
|
175
187
|
# TCP port bind for listening for bark RPC calls
|
|
188
|
+
# CLI: --bark-port
|
|
176
189
|
barkPort: 0
|
|
177
190
|
|
|
178
191
|
# ---
|
|
@@ -218,6 +231,7 @@ intersectTip: false
|
|
|
218
231
|
# Maximum total size (in bytes) of all transactions allowed in the mempool.
|
|
219
232
|
# Transactions exceeding this limit will be rejected.
|
|
220
233
|
# Default: 1048576 (1 MB)
|
|
234
|
+
# CLI: --mempool-capacity
|
|
221
235
|
mempoolCapacity: 1048576
|
|
222
236
|
|
|
223
237
|
# Forging tolerances (0 = defaults)
|
|
@@ -234,12 +248,14 @@ forgeStaleGapThresholdSlots: 0
|
|
|
234
248
|
# Note: CLI commands (serve, load) take priority over this setting
|
|
235
249
|
#
|
|
236
250
|
# Can be overridden with the DINGO_RUN_MODE environment variable
|
|
251
|
+
# CLI: --run-mode
|
|
237
252
|
runMode: "serve"
|
|
238
253
|
|
|
239
254
|
# Path to ImmutableDB for batch import (used when runMode is "load")
|
|
240
255
|
# Can also be provided as argument to 'dingo load' command
|
|
241
256
|
#
|
|
242
257
|
# Can be overridden with the DINGO_IMMUTABLE_DB_PATH environment variable
|
|
258
|
+
# CLI: --immutable-db-path
|
|
243
259
|
immutableDbPath: ""
|
|
244
260
|
|
|
245
261
|
# Validate historical blocks during ledger processing (default: false)
|
|
@@ -251,10 +267,13 @@ validateHistorical: false
|
|
|
251
267
|
# Default: known=150, established=50, active=20
|
|
252
268
|
#
|
|
253
269
|
# Target number of known (cold) peers
|
|
270
|
+
# CLI: --target-known-peers
|
|
254
271
|
targetNumberOfKnownPeers: 0
|
|
255
272
|
# Target number of established (warm) peers
|
|
273
|
+
# CLI: --target-established-peers
|
|
256
274
|
targetNumberOfEstablishedPeers: 0
|
|
257
275
|
# Target number of active (hot) peers
|
|
276
|
+
# CLI: --target-active-peers
|
|
258
277
|
targetNumberOfActivePeers: 0
|
|
259
278
|
|
|
260
279
|
# Per-source quotas for active peers
|
|
@@ -269,11 +288,52 @@ activePeersGossipQuota: 0
|
|
|
269
288
|
# Active peer slots for ledger sources
|
|
270
289
|
activePeersLedgerQuota: 0
|
|
271
290
|
|
|
291
|
+
# Inbound peer governance budget (phase 1)
|
|
292
|
+
# These define explicit operator intent for inbound peers as a governed source.
|
|
293
|
+
# Current behavior remains conservative; these values are surfaced in metrics and
|
|
294
|
+
# quota/status output to make inbound policy visible.
|
|
295
|
+
#
|
|
296
|
+
# Target number of inbound peers to keep in warm state.
|
|
297
|
+
# CLI: --inbound-warm-target
|
|
298
|
+
inboundWarmTarget: 0
|
|
299
|
+
# Quota for inbound peers in hot state.
|
|
300
|
+
# CLI: --inbound-hot-quota
|
|
301
|
+
inboundHotQuota: 0
|
|
302
|
+
# Minimum tenure before inbound peers are eligible for hot promotion.
|
|
303
|
+
# CLI: --inbound-min-tenure
|
|
304
|
+
inboundMinTenure: 0s
|
|
305
|
+
# Minimum score threshold for inbound hot promotion.
|
|
306
|
+
# CLI: --inbound-hot-score-threshold
|
|
307
|
+
inboundHotScoreThreshold: 0
|
|
308
|
+
# Future prune grace window for inbound peers.
|
|
309
|
+
# CLI: --inbound-prune-after
|
|
310
|
+
inboundPruneAfter: 0s
|
|
311
|
+
# Future duplex policy knob for inbound peers.
|
|
312
|
+
# CLI: --inbound-duplex-only-for-hot
|
|
313
|
+
inboundDuplexOnlyForHot: false
|
|
314
|
+
# Future cooldown knob for inbound peer governance actions.
|
|
315
|
+
# CLI: --inbound-cooldown
|
|
316
|
+
inboundCooldown: 0s
|
|
317
|
+
|
|
318
|
+
# Genesis bootstrap configuration
|
|
319
|
+
# Used only for from-origin sync. Default behavior keeps this enabled and
|
|
320
|
+
# exits Genesis mode automatically near the best known peer tip.
|
|
321
|
+
genesisBootstrap:
|
|
322
|
+
# Enable/disable Genesis bootstrap mode (default: true).
|
|
323
|
+
enabled: true
|
|
324
|
+
# Override the Genesis comparison window in slots.
|
|
325
|
+
# 0 auto-derives the window from genesis params (3k/f).
|
|
326
|
+
windowSlots: 0
|
|
327
|
+
# Minimum diversity groups to prefer while promoting peers during bootstrap.
|
|
328
|
+
# 0 uses the peer-governor default.
|
|
329
|
+
promotionMinDiversityGroups: 0
|
|
330
|
+
|
|
272
331
|
# Cache configuration for tiered CBOR cache system
|
|
273
332
|
# This controls the in-memory caching of UTxO and transaction CBOR data
|
|
274
333
|
cache:
|
|
275
334
|
# Number of entries in the hot UTxO cache (LFU eviction)
|
|
276
335
|
# Default: 50000
|
|
336
|
+
# CLI: --cache-hot-utxo-entries
|
|
277
337
|
hotUtxoEntries: 50000
|
|
278
338
|
# Number of entries in the hot transaction cache (LFU eviction)
|
|
279
339
|
# Default: 10000
|
|
@@ -283,16 +343,19 @@ cache:
|
|
|
283
343
|
hotTxMaxBytes: 268435456
|
|
284
344
|
# Number of blocks to keep in the block LRU cache
|
|
285
345
|
# Default: 500
|
|
346
|
+
# CLI: --cache-block-lru-entries
|
|
286
347
|
blockLruEntries: 500
|
|
287
348
|
# Number of recent blocks to warm up on startup
|
|
288
349
|
# Default: 1000
|
|
289
350
|
warmupBlocks: 1000
|
|
290
351
|
# Wait for cache warmup to complete before serving requests
|
|
291
352
|
# Default: true
|
|
353
|
+
# CLI: --cache-warmup-sync
|
|
292
354
|
warmupSync: true
|
|
293
355
|
|
|
294
356
|
# Mithril snapshot bootstrap configuration
|
|
295
357
|
# Use 'dingo mithril sync' or 'dingo sync --mithril' to bootstrap from a snapshot
|
|
358
|
+
# CLI: --mithril-enabled, --mithril-verify-certs
|
|
296
359
|
mithril:
|
|
297
360
|
# Enable Mithril integration (default: true)
|
|
298
361
|
enabled: true
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# Dingo Grafana Dashboards
|
|
2
|
+
|
|
3
|
+
Monitoring dashboards for [Dingo](https://github.com/blinklabs-io/dingo), the Go Cardano node by Blink Labs.
|
|
4
|
+
|
|
5
|
+
## Dashboards
|
|
6
|
+
|
|
7
|
+
| Dashboard | File | Description |
|
|
8
|
+
|-----------|------|-------------|
|
|
9
|
+
| **Node Overview** | `node-overview.json` | At-a-glance header (epoch, slot, tip gap, density, blockfetch, mempool, KES, peers, storage, runtime), block height, epoch progress, forging stats |
|
|
10
|
+
| **Block Production** | `block-production.json` | Forge latency heatmap, block delay CDFs, forge rates, KES lifecycle |
|
|
11
|
+
| **Peer Health** | `peer-health.json` | Hot/warm/cold peers, connection types, peer state timeseries, promotions/demotions, network I/O |
|
|
12
|
+
| **Mempool** | `mempool.json` | Pending TXs, mempool size, TX lifecycle, CBOR cache, event bus |
|
|
13
|
+
| **Resource Usage** | `resources.json` | CPU, memory, GC heatmap, disk I/O, IOPS, PSI pressure, Badger, file descriptors |
|
|
14
|
+
|
|
15
|
+
`full-panel.json` contains the standalone Business Text header panel for embedding into custom dashboards.
|
|
16
|
+
|
|
17
|
+
## Prerequisites
|
|
18
|
+
|
|
19
|
+
Before you begin, make sure you have:
|
|
20
|
+
|
|
21
|
+
- **Grafana 12+** (tested on 12.4) — [install guide](https://grafana.com/docs/grafana/latest/setup-grafana/installation/)
|
|
22
|
+
- **Prometheus** scraping your Dingo node on port `12798` (configured in step 2 below)
|
|
23
|
+
- **Dingo** node with metrics enabled (default port `12798`)
|
|
24
|
+
- **[Business Text plugin](https://grafana.com/grafana/plugins/marcusolsson-dynamictext-panel/)** — required by all dashboards for the header panel
|
|
25
|
+
- **[prometheus-node-exporter](https://github.com/prometheus/node_exporter)** — required only by the Resource Usage dashboard for host-level CPU, memory, and disk metrics
|
|
26
|
+
|
|
27
|
+
## Quick start
|
|
28
|
+
|
|
29
|
+
### 1. Install the Business Text plugin
|
|
30
|
+
|
|
31
|
+
Open a terminal on the machine running Grafana and run:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
grafana-cli plugins install marcusolsson-dynamictext-panel
|
|
35
|
+
sudo systemctl restart grafana-server
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
If you are running Grafana in Docker or Kubernetes, set the environment variable instead:
|
|
39
|
+
|
|
40
|
+
```text
|
|
41
|
+
GF_INSTALL_PLUGINS=marcusolsson-dynamictext-panel
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 2. Configure Prometheus scrape targets
|
|
45
|
+
|
|
46
|
+
Prometheus needs to know where to find your Dingo node. Add the following to your `prometheus.yml` under `scrape_configs`:
|
|
47
|
+
|
|
48
|
+
```yaml
|
|
49
|
+
- job_name: dingo
|
|
50
|
+
scrape_interval: 15s
|
|
51
|
+
static_configs:
|
|
52
|
+
- targets: ['localhost:12798']
|
|
53
|
+
|
|
54
|
+
# Optional: required for Resource Usage dashboard
|
|
55
|
+
- job_name: node
|
|
56
|
+
scrape_interval: 15s
|
|
57
|
+
static_configs:
|
|
58
|
+
- targets: ['localhost:9100']
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Then reload Prometheus to apply the change:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
sudo systemctl reload prometheus
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 3. Import dashboards
|
|
68
|
+
|
|
69
|
+
There are two ways to get the dashboards into Grafana.
|
|
70
|
+
|
|
71
|
+
**Option A: Provisioning (recommended)**
|
|
72
|
+
|
|
73
|
+
Provisioning automatically loads dashboards from files on disk. Grafana will pick them up on startup or within about 30 seconds if already running.
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
sudo cp docs/dashboards/provisioning.yaml /etc/grafana/provisioning/dashboards/dingo.yaml
|
|
77
|
+
sudo mkdir -p /var/lib/grafana/dashboards/dingo
|
|
78
|
+
sudo cp docs/dashboards/*.json /var/lib/grafana/dashboards/dingo/
|
|
79
|
+
sudo chown -R grafana:grafana /var/lib/grafana/dashboards/dingo/
|
|
80
|
+
sudo systemctl restart grafana-server
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
After restarting, go to **Dashboards → Browse** in the Grafana UI and search for "Dingo". All five dashboards appear in a **Dingo** folder automatically.
|
|
84
|
+
|
|
85
|
+
**Note:** `allowUiUpdates: true` lets you edit dashboards in the Grafana UI, but changes will be overwritten on the next provision cycle (every 30 seconds). To make permanent edits, modify the JSON files directly.
|
|
86
|
+
|
|
87
|
+
**Option B: Manual import**
|
|
88
|
+
|
|
89
|
+
1. Open Grafana in your browser
|
|
90
|
+
2. Go to **Dashboards → New → Import**
|
|
91
|
+
3. Upload each JSON file
|
|
92
|
+
4. Select your Prometheus datasource when prompted
|
|
93
|
+
|
|
94
|
+
### 4. Alert rules (optional)
|
|
95
|
+
|
|
96
|
+
The alert rules file is ready to use as-is — no editing required.
|
|
97
|
+
|
|
98
|
+
Copy the file to your Prometheus rules directory:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
sudo cp docs/dashboards/alerts.yaml /etc/prometheus/rules/dingo.yaml
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Then add it to `prometheus.yml`:
|
|
105
|
+
|
|
106
|
+
```yaml
|
|
107
|
+
rule_files:
|
|
108
|
+
- /etc/prometheus/rules/dingo.yaml
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Reload Prometheus:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
sudo systemctl reload prometheus
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Datasource
|
|
118
|
+
|
|
119
|
+
All dashboards expect a Prometheus datasource with UID `prometheus`. If your datasource has a different UID, update it before importing or recreate the datasource with UID `prometheus`.
|
|
120
|
+
|
|
121
|
+
## Template variables
|
|
122
|
+
|
|
123
|
+
All dashboards include two template variables that auto-discover dingo instances:
|
|
124
|
+
|
|
125
|
+
| Variable | Query | Purpose |
|
|
126
|
+
|----------|-------|---------|
|
|
127
|
+
| `$network` | `label_values(dingo_build_info, network)` | Selects the Cardano network (`preview`, `preprod`, `mainnet`). |
|
|
128
|
+
| `$instance` | `label_values(dingo_build_info{network="$network"}, instance)` | Selects specific dingo instance(s). Multi-select with "All" default. |
|
|
129
|
+
|
|
130
|
+
`dingo_build_info` is a metric only dingo exposes (includes `network`, `version`, `commit` labels). This ensures dropdowns show only dingo targets, never Haskell cardano-node.
|
|
131
|
+
|
|
132
|
+
All panel queries use `{network="$network", instance=~"$instance"}` as their selector.
|
|
133
|
+
|
|
134
|
+
The **Resource Usage** dashboard adds a third variable:
|
|
135
|
+
|
|
136
|
+
| Variable | Query | Purpose |
|
|
137
|
+
|----------|-------|---------|
|
|
138
|
+
| `$node_instance` | `label_values(node_uname_info, instance)` | Selects the node_exporter target for host-level metrics (CPU, memory, disk, network). node_exporter runs on a different port (default `9100`) from the dingo metrics port, so it needs its own instance dropdown. |
|
|
139
|
+
|
|
140
|
+
Set `$node_instance` to the hostname/port reported by your node_exporter scrape target (typically `localhost:9100` or the host IP).
|
|
141
|
+
|
|
142
|
+
## Navigation
|
|
143
|
+
|
|
144
|
+
Dashboard-level links at the top of each dashboard connect all 5 dashboards. Links preserve the selected time range and template variables.
|
|
145
|
+
|
|
146
|
+
## Dormant metrics
|
|
147
|
+
|
|
148
|
+
Some metrics only emit when their feature is active. Panels display "No data" until activated:
|
|
149
|
+
|
|
150
|
+
| Metric | Activates when |
|
|
151
|
+
|--------|---------------|
|
|
152
|
+
| `cardano_node_metrics_Forge_node_is_leader_int` | Forging is enabled |
|
|
153
|
+
| `cardano_node_metrics_Forge_adopted_int` | Block is forged and adopted |
|
|
154
|
+
| `cardano_node_metrics_blockForgingLatency_seconds_bucket` | Block is forged |
|
|
155
|
+
| `cardano_node_metrics_remainingKESPeriods_int` | KES key is configured |
|
|
156
|
+
| `dingo_forge_tip_gap_slots` | Forging is enabled |
|
|
157
|
+
| `dingo_database_size_bytes` | Database stores are initialized |
|
|
158
|
+
| `database_blob_*` | Badger blob store is active |
|
|
159
|
+
|
|
160
|
+
## File listing
|
|
161
|
+
|
|
162
|
+
```text
|
|
163
|
+
docs/dashboards/
|
|
164
|
+
node-overview.json Node Overview dashboard
|
|
165
|
+
block-production.json Block Production dashboard
|
|
166
|
+
peer-health.json Peer Health dashboard
|
|
167
|
+
mempool.json Mempool dashboard
|
|
168
|
+
resources.json Resource Usage dashboard
|
|
169
|
+
full-panel.json Business Text header panel (standalone)
|
|
170
|
+
provisioning.yaml Grafana provisioning config
|
|
171
|
+
prometheus.yaml Prometheus scrape config snippet
|
|
172
|
+
alerts.yaml Prometheus alert rules
|
|
173
|
+
README.md This file
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Troubleshooting
|
|
177
|
+
|
|
178
|
+
**Business Text plugin not found / panels show "Panel plugin not found: marcusolsson-dynamictext-panel"**
|
|
179
|
+
Install the plugin (step 1 above) and restart Grafana. If running in a managed environment, add `marcusolsson-dynamictext-panel` to your `GF_INSTALL_PLUGINS` list.
|
|
180
|
+
|
|
181
|
+
**Panels show "No data"**
|
|
182
|
+
Check that Prometheus is scraping your Dingo node: open Prometheus in the browser, go to **Status → Targets**, and confirm the `dingo` job is up. Also verify the `$network` and `$instance` template variables at the top of the dashboard are set to the correct values.
|
|
183
|
+
|
|
184
|
+
**Datasource UID mismatch ("datasource not found")**
|
|
185
|
+
All JSON files use the datasource UID `prometheus`. If your Prometheus datasource has a different UID, either rename it to `prometheus` in **Connections → Data sources**, or do a find-and-replace of `"prometheus"` with your actual UID in the JSON files before importing.
|
|
186
|
+
|
|
187
|
+
**Dashboards not appearing after provisioning**
|
|
188
|
+
Confirm `/etc/grafana/provisioning/dashboards/dingo.yaml` references the correct path. Grafana auto-reloads provisioned dashboards every 30 seconds; if it hasn't appeared after a minute, check the Grafana log (`journalctl -u grafana-server`) for errors.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
groups:
|
|
2
|
+
- name: dingo
|
|
3
|
+
rules:
|
|
4
|
+
- alert: DingoBlockStall
|
|
5
|
+
expr: changes(cardano_node_metrics_blockNum_int{network=~".+"}[5m]) == 0
|
|
6
|
+
for: 0m
|
|
7
|
+
labels:
|
|
8
|
+
severity: warning
|
|
9
|
+
annotations:
|
|
10
|
+
summary: "Dingo block height stalled on {{ $labels.network }}"
|
|
11
|
+
description: "Node {{ $labels.instance }} on {{ $labels.network }}: block height has not changed in 5 minutes."
|
|
12
|
+
|
|
13
|
+
- alert: DingoSlotDrift
|
|
14
|
+
expr: changes(cardano_node_metrics_slotNum_int{network=~".+"}[2m]) == 0
|
|
15
|
+
for: 0m
|
|
16
|
+
labels:
|
|
17
|
+
severity: warning
|
|
18
|
+
annotations:
|
|
19
|
+
summary: "Dingo slot counter stalled on {{ $labels.network }}"
|
|
20
|
+
description: "Node {{ $labels.instance }} on {{ $labels.network }}: slot counter has not advanced in 2 minutes."
|
|
21
|
+
|
|
22
|
+
- alert: DingoPeerLoss
|
|
23
|
+
expr: cardano_node_metrics_connectionManager_outgoingConns{network=~".+"} == 0
|
|
24
|
+
for: 5m
|
|
25
|
+
labels:
|
|
26
|
+
severity: critical
|
|
27
|
+
annotations:
|
|
28
|
+
summary: "Dingo has no outgoing peers on {{ $labels.network }}"
|
|
29
|
+
description: "Node {{ $labels.instance }} on {{ $labels.network }}: zero outgoing connections for 5+ minutes. Node cannot sync."
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
## Prometheus scrape configuration for Dingo dashboards
|
|
2
|
+
##
|
|
3
|
+
## Add these jobs to your prometheus.yml under scrape_configs:
|
|
4
|
+
|
|
5
|
+
scrape_configs:
|
|
6
|
+
# Dingo node metrics (default port 12798)
|
|
7
|
+
- job_name: dingo
|
|
8
|
+
scrape_interval: 15s
|
|
9
|
+
static_configs:
|
|
10
|
+
- targets: ['localhost:12798']
|
|
11
|
+
|
|
12
|
+
# Node exporter for host-level metrics (required by Resource Usage dashboard)
|
|
13
|
+
- job_name: node
|
|
14
|
+
scrape_interval: 15s
|
|
15
|
+
static_configs:
|
|
16
|
+
- targets: ['localhost:9100']
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
apiVersion: 1
|
|
2
|
+
|
|
3
|
+
providers:
|
|
4
|
+
- name: dingo
|
|
5
|
+
orgId: 1
|
|
6
|
+
folder: Dingo
|
|
7
|
+
folderUid: dingo-dashboards
|
|
8
|
+
type: file
|
|
9
|
+
disableDeletion: false
|
|
10
|
+
updateIntervalSeconds: 30
|
|
11
|
+
allowUiUpdates: true
|
|
12
|
+
options:
|
|
13
|
+
path: /var/lib/grafana/dashboards/dingo
|
|
14
|
+
foldersFromFilesStructure: false
|