@blinklabs/dingo 0.20.0 → 0.23.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/README.md CHANGED
@@ -9,11 +9,22 @@
9
9
  <a href="https://discord.gg/5fPRZnX4qW"><img src="https://img.shields.io/badge/Discord-7289DA?style=flat&logo=discord&logoColor=white" alt="Discord"></a>
10
10
  </div>
11
11
 
12
- # Dingo
13
-
14
- ⚠️ This is a work in progress and is currently under heavy development
15
-
16
- **Note:** On Windows systems, named pipes are used instead of Unix sockets for node-to-client communication.
12
+ > ⚠️ **WARNING: Dingo is under heavy active development and is not yet ready for production use. It should only be used on testnets (preview, preprod) and devnets. Do not use Dingo on mainnet with real funds.**
13
+
14
+ A high-performance Cardano blockchain node implementation in Go by Blink Labs. Dingo provides:
15
+ - Full chain synchronization and validation via Ouroboros consensus protocol
16
+ - UTxO tracking with 41 UTXO validation rules and Plutus V1/V2/V3 smart contract execution
17
+ - Block production with VRF leader election and stake snapshots
18
+ - Multi-peer chain selection with density comparison and VRF tie-breaking
19
+ - Client connectivity for wallets and applications
20
+ - Pluggable storage backends (Badger, SQLite, PostgreSQL, MySQL, GCS, S3)
21
+ - Tiered storage modes ("core" for consensus, "api" for full indexing)
22
+ - Peer governance with dynamic peer selection, ledger peers, and topology support
23
+ - Chain rollback support for handling forks with automatic state restoration
24
+ - Fast bootstrapping via built-in Mithril client
25
+ - Multiple API servers: UTxO RPC, Blockfrost-compatible REST, Mesh (Coinbase Rosetta)
26
+
27
+ Note: On Windows systems, named pipes are used instead of Unix sockets for node-to-client communication.
17
28
 
18
29
  <div align="center">
19
30
  <img src="./.github/dingo-20241210.png" alt="dingo screenshot" width="640">
@@ -21,11 +32,13 @@
21
32
 
22
33
  ## Running
23
34
 
24
- Dingo supports configuration via both a YAML config file (`dingo.yaml`) and uses environment
25
- variables to modify its own behavior.
35
+ Dingo supports configuration via a YAML config file (`dingo.yaml`), environment variables, and command-line flags. Priority: CLI flags > environment variables > YAML config > defaults.
36
+
37
+ A sample configuration file is provided at `dingo.yaml.example`. You can copy and edit this file to configure Dingo for your local or production environment.
38
+
39
+ ### Environment Variables
26
40
 
27
- A sample configuration file is provided at `dingo.yaml.example`.You can copy and edit this file to configure Dingo for your local or production environment:
28
- This behavior can be changed via the following environment variables:
41
+ The following environment variables modify Dingo's behavior:
29
42
 
30
43
  - `CARDANO_BIND_ADDR`
31
44
  - IP address to bind for listening (default: `0.0.0.0`)
@@ -58,25 +71,292 @@ This behavior can be changed via the following environment variables:
58
71
  - This socket speaks Ouroboros NtC and is used by client software
59
72
  - `CARDANO_TOPOLOGY`
60
73
  - Full path to the Cardano node topology (default: "")
61
- - `CARDANO_UTXORPC_PORT`
62
- - TCP port to bind for listening for UTxO RPC (default: `9090`)
74
+ - `DINGO_UTXORPC_PORT`
75
+ - TCP port to bind for listening for UTxO RPC (default: `0`, disabled)
76
+ - `DINGO_BLOCKFROST_PORT`
77
+ - TCP port for the Blockfrost-compatible REST API (default: `0`, disabled)
78
+ - `DINGO_MESH_PORT`
79
+ - TCP port for the Mesh (Coinbase Rosetta) API (default: `0`, disabled)
80
+ - `DINGO_BARK_PORT`
81
+ - TCP port for the Bark block archive API (default: `0`, disabled)
82
+ - `DINGO_STORAGE_MODE`
83
+ - Storage mode: `core` (default) or `api`
84
+ - `core` stores only consensus data (UTxOs, certs, pools, protocol params)
85
+ - `api` additionally stores witnesses, scripts, datums, redeemers, and tx metadata
86
+ - API servers (Blockfrost, UTxO RPC, Mesh) require `api` mode
87
+ - `DINGO_RUN_MODE`
88
+ - Run mode: `serve` (full node, default), `load` (batch import), `dev` (development mode), or `leios` (experimental Leios protocol support)
63
89
  - `TLS_CERT_FILE_PATH` - SSL certificate to use, requires `TLS_KEY_FILE_PATH`
64
90
  (default: empty)
65
91
  - `TLS_KEY_FILE_PATH` - SSL certificate key to use (default: empty)
66
92
 
93
+ ### Block Production (SPO Mode)
94
+
95
+ To run Dingo as a stake pool operator producing blocks:
96
+
97
+ - `CARDANO_BLOCK_PRODUCER` - Enable block production (default: `false`)
98
+ - `CARDANO_SHELLEY_VRF_KEY` - Path to VRF signing key file
99
+ - `CARDANO_SHELLEY_KES_KEY` - Path to KES signing key file
100
+ - `CARDANO_SHELLEY_OPERATIONAL_CERTIFICATE` - Path to operational certificate file
101
+
102
+ ### Quick Start
103
+
104
+ ```bash
105
+ # Preview network (default)
106
+ ./dingo
107
+
108
+ # Mainnet
109
+ CARDANO_NETWORK=mainnet ./dingo
110
+
111
+ # Or with explicit config path
112
+ CARDANO_NETWORK=mainnet CARDANO_CONFIG=path/to/mainnet/config.json ./dingo
113
+ ```
114
+
115
+ Dingo creates a `dingo.socket` file that speaks Ouroboros node-to-client and is compatible with `cardano-cli`, `adder`, `kupo`, and other Cardano client tools.
116
+
117
+ Cardano configuration files are bundled in the Docker image. For local builds, you can find them at [docker-cardano-configs](https://github.com/blinklabs-io/docker-cardano-configs/tree/main/config).
118
+
119
+ ## Docker
120
+
121
+ ```bash
122
+ # Run on preview (default)
123
+ docker run -p 3001:3001 ghcr.io/blinklabs-io/dingo
124
+
125
+ # Run on mainnet with persistent storage
126
+ docker run -p 3001:3001 \
127
+ -e CARDANO_NETWORK=mainnet \
128
+ -v dingo-data:/data/db \
129
+ -v dingo-ipc:/ipc \
130
+ ghcr.io/blinklabs-io/dingo
131
+ ```
132
+
133
+ The image is based on Debian bookworm-slim and includes `cardano-cli`, `mithril-client`, `nview`, and `txtop`. The Dockerfile sets `CARDANO_DATABASE_PATH=/data/db` and `CARDANO_SOCKET_PATH=/ipc/dingo.socket`, overriding the local defaults of `.dingo` and `dingo.socket` — the volume mounts above map to these container paths.
134
+
135
+ | Port | Service |
136
+ |------|---------|
137
+ | 3001 | Ouroboros NtN (node-to-node) |
138
+ | 3002 | Ouroboros NtC over TCP |
139
+ | 12798 | Prometheus metrics |
140
+
141
+ ## Storage Modes
142
+
143
+ Dingo has two storage modes that control how much data is persisted:
144
+
145
+ | Mode | What's Stored | Use Case |
146
+ |------|---------------|----------|
147
+ | `core` (default) | UTxOs, certificates, pools, protocol parameters | Relays, block producers |
148
+ | `api` | Core data + witnesses, scripts, datums, redeemers, tx metadata | Nodes serving API queries |
149
+
150
+ ```bash
151
+ # Relay or block producer (default)
152
+ ./dingo
153
+
154
+ # API node
155
+ DINGO_STORAGE_MODE=api ./dingo
156
+ ```
157
+
158
+ Or in `dingo.yaml`:
159
+
160
+ ```yaml
161
+ storageMode: "api"
162
+ ```
163
+
164
+ ## API Servers
165
+
166
+ Dingo includes four API servers, all disabled by default. Enable them by setting a non-zero port. All API servers except Bark require `storageMode: "api"`.
167
+
168
+ | API | Port Env Var | Default | Protocol |
169
+ |-----|-------------|---------|----------|
170
+ | UTxO RPC | `DINGO_UTXORPC_PORT` | disabled | gRPC |
171
+ | Blockfrost | `DINGO_BLOCKFROST_PORT` | disabled | REST |
172
+ | Mesh (Rosetta) | `DINGO_MESH_PORT` | disabled | REST |
173
+ | Bark | `DINGO_BARK_PORT` | disabled | RPC |
174
+
175
+ ```bash
176
+ # Enable Blockfrost API on port 3100 and UTxO RPC on port 9090
177
+ DINGO_STORAGE_MODE=api \
178
+ DINGO_BLOCKFROST_PORT=3100 \
179
+ DINGO_UTXORPC_PORT=9090 \
180
+ ./dingo
181
+ ```
182
+
183
+ Or in `dingo.yaml`:
184
+
185
+ ```yaml
186
+ storageMode: "api"
187
+ blockfrostPort: 3100
188
+ utxorpcPort: 9090
189
+ ```
190
+
191
+ ### Deployment Patterns
192
+
193
+ **Relay node** (consensus only, no APIs):
194
+ ```bash
195
+ ./dingo
196
+ ```
197
+
198
+ **API / data node** (full indexing, one or more APIs):
199
+ ```bash
200
+ DINGO_STORAGE_MODE=api DINGO_BLOCKFROST_PORT=3100 ./dingo
201
+ ```
202
+
203
+ **Block producer** (consensus only, with SPO keys):
204
+ ```bash
205
+ CARDANO_BLOCK_PRODUCER=true \
206
+ CARDANO_SHELLEY_VRF_KEY=/keys/vrf.skey \
207
+ CARDANO_SHELLEY_KES_KEY=/keys/kes.skey \
208
+ CARDANO_SHELLEY_OPERATIONAL_CERTIFICATE=/keys/opcert.cert \
209
+ ./dingo
210
+ ```
211
+
212
+ See `dingo.yaml.example` for the full set of configuration options.
213
+
214
+ ## Fast Bootstrapping with Mithril
215
+
216
+ Instead of syncing from genesis (which can take days on mainnet), you can bootstrap Dingo using a [Mithril](https://mithril.network/) snapshot. There are two approaches depending on your use case:
217
+
218
+ | Approach | Command | Use Case | Data Available |
219
+ |----------|---------|----------|---------------|
220
+ | `dingo sync --mithril` | `dingo sync --mithril` | Consensus nodes, relays | Current ledger state + all blocks |
221
+ | `mithril-client` + `dingo load` | Manual download + load | Indexers, API nodes | Full historical transaction/certificate data |
222
+
223
+ ### Option 1: `dingo sync --mithril` (Recommended for Consensus)
224
+
225
+ Dingo has a built-in Mithril client that handles download, extraction, and import automatically. This is the fastest way to get a node running.
226
+
227
+ ```bash
228
+ # Bootstrap from Mithril and start syncing
229
+ ./dingo -n preview sync --mithril
230
+
231
+ # Then start the node
232
+ ./dingo -n preview serve
233
+ ```
234
+
235
+ Or use the subcommand form for more control:
236
+
237
+ ```bash
238
+ # List available snapshots
239
+ ./dingo -n preview mithril list
240
+
241
+ # Show snapshot details
242
+ ./dingo -n preview mithril show <digest>
243
+
244
+ # Download and import
245
+ ./dingo -n preview mithril sync
246
+ ```
247
+
248
+ This imports:
249
+ - All blocks from genesis (stored in blob store for serving peers)
250
+ - Current UTxO set, stake accounts, pool registrations, DRep registrations
251
+ - Stake snapshots (mark/set/go) for leader election
252
+ - Protocol parameters, governance state, treasury/reserves
253
+ - Complete epoch history for slot-to-time calculations
254
+
255
+ What is NOT included: Individual transaction records, certificate history, witness/script/datum storage, and governance vote records for blocks before the snapshot. These are not needed for consensus, block production, or serving blocks to peers. New blocks processed after bootstrap will have full metadata.
256
+
257
+ Performance (preview network, ~4M blocks):
258
+
259
+ | Phase | Time |
260
+ |-------|------|
261
+ | Download snapshot (~2.6 GB) | ~1-2 min |
262
+ | Extract + download ancillary | ~1 min |
263
+ | Import ledger state (UTxOs, accounts, pools, DReps, epochs) | ~12 min |
264
+ | Load blocks into blob store | ~36 min |
265
+ | Total | ~50 min |
266
+
267
+ ### Option 2: `mithril-client` + `dingo load` (For Indexers/API Nodes)
268
+
269
+ If you need full historical data (transaction lookups, certificate queries, datum/script resolution), use the external `mithril-client` to download the snapshot and then load it with `dingo load`, which processes every block through the full indexing pipeline.
270
+
271
+ #### Prerequisites
272
+
273
+ Install the `mithril-client` CLI from [Mithril releases](https://github.com/input-output-hk/mithril/releases):
274
+
275
+ ```bash
276
+ # Detect OS and architecture
277
+ OS=$(uname -s)
278
+ ARCH=$(uname -m)
279
+
280
+ case "$OS" in
281
+ Linux)
282
+ case "$ARCH" in
283
+ x86_64) MITHRIL_PLATFORM="x64-linux-musl" ;;
284
+ aarch64|arm64) MITHRIL_PLATFORM="arm64-linux-musl" ;;
285
+ *) echo "Unsupported architecture: $ARCH"; exit 1 ;;
286
+ esac
287
+ ;;
288
+ Darwin)
289
+ case "$ARCH" in
290
+ x86_64) MITHRIL_PLATFORM="x64-macos" ;;
291
+ arm64) MITHRIL_PLATFORM="arm64-macos" ;;
292
+ *) echo "Unsupported architecture: $ARCH"; exit 1 ;;
293
+ esac
294
+ ;;
295
+ *) echo "Unsupported OS: $OS (see Mithril releases for Windows)"; exit 1 ;;
296
+ esac
297
+
298
+ MITHRIL_VERSION="2506.0"
299
+ curl -L "https://github.com/input-output-hk/mithril/releases/download/${MITHRIL_VERSION}/mithril-${MITHRIL_VERSION}-${MITHRIL_PLATFORM}.tar.gz" -o mithril.tar.gz
300
+ tar -xzf mithril.tar.gz
301
+ sudo mv mithril-client /usr/local/bin/
302
+ rm mithril.tar.gz
303
+ ```
304
+
305
+ For Windows, download the appropriate binary from the [Mithril releases page](https://github.com/input-output-hk/mithril/releases).
306
+
307
+ #### Bootstrap Workflow
308
+
309
+ ```bash
310
+ # Set network (CARDANO_NETWORK is used by dingo, not mithril-client)
311
+ export CARDANO_NETWORK=preview
312
+ # AGGREGATOR_ENDPOINT is used by mithril-client
313
+ export AGGREGATOR_ENDPOINT=https://aggregator.pre-release-preview.api.mithril.network/aggregator
314
+
315
+ # For mainnet:
316
+ # export AGGREGATOR_ENDPOINT=https://aggregator.release-mainnet.api.mithril.network/aggregator
317
+
318
+ # Download snapshot (uses AGGREGATOR_ENDPOINT)
319
+ mithril-client cardano-db download --download-dir /tmp/mithril-snapshot
320
+
321
+ # Load into Dingo (uses CARDANO_NETWORK for chain config)
322
+ ./dingo load /tmp/mithril-snapshot/db/immutable
323
+
324
+ # Clean up snapshot
325
+ rm -rf /tmp/mithril-snapshot
326
+
327
+ # Start Dingo
328
+ ./dingo -n preview serve
329
+ ```
330
+
331
+ This creates full historical data including transaction records, certificate history, witness data, scripts, datums, and governance votes -- everything needed for rich query APIs.
332
+
333
+ ### Disk Space Requirements
334
+
335
+ Bootstrapping requires temporary disk space for both the downloaded snapshot and the Dingo database:
336
+
337
+ | Network | Snapshot Size | Dingo DB | Total Needed |
338
+ |---------|--------------|----------|--------------|
339
+ | mainnet | ~180 GB | ~200+ GB | ~400 GB |
340
+ | preprod | ~60 GB | ~80 GB | ~150 GB |
341
+ | preview | ~15 GB | ~25 GB | ~50 GB |
342
+
343
+ These are approximate values that grow over time. The snapshot can be deleted after import, but you need sufficient space for both during the load process.
344
+
67
345
  ## Database Plugins
68
346
 
69
347
  Dingo supports pluggable storage backends for both blob storage (blocks, transactions) and metadata storage. This allows you to choose the best storage solution for your use case.
70
348
 
71
349
  ### Available Plugins
72
350
 
73
- **Blob Storage Plugins:**
351
+ Blob Storage Plugins:
74
352
  - `badger` - BadgerDB local key-value store (default)
75
353
  - `gcs` - Google Cloud Storage blob store
76
354
  - `s3` - AWS S3 blob store
77
355
 
78
- **Metadata Storage Plugins:**
356
+ Metadata Storage Plugins:
79
357
  - `sqlite` - SQLite relational database (default)
358
+ - `postgres` - PostgreSQL relational database
359
+ - `mysql` - MySQL relational database
80
360
 
81
361
  ### Plugin Selection
82
362
 
@@ -102,27 +382,45 @@ database:
102
382
 
103
383
  Each plugin supports specific configuration options. See `dingo.yaml.example` for detailed configuration examples.
104
384
 
105
- **BadgerDB Options:**
385
+ BadgerDB Options:
106
386
  - `data-dir` - Directory for database files
107
387
  - `block-cache-size` - Block cache size in bytes
108
388
  - `index-cache-size` - Index cache size in bytes
109
389
  - `gc` - Enable garbage collection
110
390
 
111
- **Google Cloud Storage Options:**
391
+ Google Cloud Storage Options:
112
392
  - `bucket` - GCS bucket name
113
393
  - `project-id` - Google Cloud project ID
114
394
  - `prefix` - Path prefix within bucket
115
395
 
116
- **AWS S3 Options:**
396
+ AWS S3 Options:
117
397
  - `bucket` - S3 bucket name
118
398
  - `region` - AWS region
119
399
  - `prefix` - Path prefix within bucket
120
400
  - `access-key-id` - AWS access key ID (optional - uses default credential chain if not provided)
121
401
  - `secret-access-key` - AWS secret access key (optional - uses default credential chain if not provided)
122
402
 
123
- **SQLite Options:**
403
+ SQLite Options:
124
404
  - `data-dir` - Path to SQLite database file
125
405
 
406
+ PostgreSQL Options:
407
+ - `host` - PostgreSQL server hostname
408
+ - `port` - PostgreSQL server port
409
+ - `username` - Database user
410
+ - `password` - Database password
411
+ - `database` - Database name
412
+
413
+ MySQL Options:
414
+ - `host` - MySQL server hostname
415
+ - `port` - MySQL server port
416
+ - `user` - Database user
417
+ - `password` - Database password
418
+ - `database` - Database name
419
+ - `ssl-mode` - MySQL TLS mode (mapped to tls= in DSN)
420
+ - `timezone` - MySQL time zone location (default: UTC)
421
+ - `dsn` - Full MySQL DSN (overrides other options when set)
422
+ - `storage-mode` - Storage tier: core or api (default: core)
423
+
126
424
  ### Listing Available Plugins
127
425
 
128
426
  You can see all available plugins and their descriptions:
@@ -135,21 +433,6 @@ You can see all available plugins and their descriptions:
135
433
 
136
434
  For information on developing custom storage plugins, see [PLUGIN_DEVELOPMENT.md](PLUGIN_DEVELOPMENT.md).
137
435
 
138
- ### Example
139
-
140
- Running on mainnet (:sweat_smile:):
141
-
142
- ```bash
143
- CARDANO_NETWORK=mainnet CARDANO_CONFIG=path/to/cardano/configs/mainnet/config.json ./dingo
144
- ```
145
-
146
- Note: you can find cardano configuration files at
147
- <https://github.com/blinklabs-io/docker-cardano-configs/tree/main/config>
148
-
149
- Dingo will drop a `dingo.socket` file which can be used by other clients, such
150
- as `cardano-cli` or software like `adder` or `kupo`. This has only had limited
151
- testing, so success/failure reports are very welcome and encouraged!
152
-
153
436
  ## Features
154
437
 
155
438
  - [x] Network
@@ -164,10 +447,12 @@ testing, so success/failure reports are very welcome and encouraged!
164
447
  - [x] LocalTxMonitor
165
448
  - [x] LocalTxSubmission
166
449
  - [x] LocalStateQuery
167
- - [ ] Peer governor
450
+ - [x] Peer governor
168
451
  - [x] Topology config
169
- - [ ] Peer churn
170
- - [ ] Ledger peers
452
+ - [x] Peer churn (full PeerChurnEvent with gossip/public root churn, bootstrap events)
453
+ - [x] Ledger peers
454
+ - [x] Peer sharing
455
+ - [x] Denied peers tracking
171
456
  - [x] Connection manager
172
457
  - [x] Inbound connections
173
458
  - [x] Node-to-client over TCP
@@ -178,29 +463,59 @@ testing, so success/failure reports are very welcome and encouraged!
178
463
  - [ ] Ledger
179
464
  - [x] Blocks
180
465
  - [x] Block storage
181
- - [ ] Chain selection
466
+ - [x] Chain selection (density comparison, VRF tie-breaker, ChainForkEvent)
182
467
  - [x] UTxO tracking
183
468
  - [x] Protocol parameters
469
+ - [x] Genesis validation
470
+ - [x] Block header validation (VRF/KES/OpCert cryptographic verification)
184
471
  - [ ] Certificates
185
472
  - [x] Pool registration
186
473
  - [x] Stake registration/delegation
474
+ - [x] Account registration checks
475
+ - [x] DRep registration
187
476
  - [ ] Governance
188
477
  - [ ] Transaction validation
189
478
  - [ ] Phase 1 validation
190
479
  - [x] UTxO rules
480
+ - [x] Fee validation (full fee calculation with script costs)
481
+ - [x] Transaction size and ExUnit budget validation
191
482
  - [ ] Witnesses
192
483
  - [ ] Block body
193
484
  - [ ] Certificates
194
485
  - [ ] Delegation/pools
195
486
  - [ ] Governance
196
- - [ ] Phase 2 validation
197
- - [ ] Smart contracts
487
+ - [x] Phase 2 validation
488
+ - [x] Plutus V1 smart contract execution
489
+ - [x] Plutus V2 smart contract execution
490
+ - [x] Plutus V3 smart contract execution
491
+ - [x] Block production
492
+ - [x] VRF leader election with stake snapshots
493
+ - [x] Block forging with KES/OpCert signing
494
+ - [x] Slot battle detection
198
495
  - [x] Mempool
199
496
  - [x] Accept transactions from local clients
200
497
  - [x] Distribute transactions to other nodes
201
498
  - [x] Validation of transaction on add
202
499
  - [x] Consumer tracking
203
500
  - [x] Transaction purging on chain update
501
+ - [x] Watermark-based eviction and rejection
502
+ - [x] Database Recovery
503
+ - [x] Chain rollback support (SQLite, PostgreSQL, and MySQL plugins)
504
+ - [x] State restoration on rollback
505
+ - [x] WAL mode for crash recovery
506
+ - [x] Automatic rollback on transaction error
507
+ - [x] Stake Snapshots
508
+ - [x] Mark/Set/Go rotation at epoch boundaries
509
+ - [x] Genesis snapshot capture
510
+ - [x] API Servers
511
+ - [x] UTxO RPC (gRPC)
512
+ - [x] Blockfrost-compatible REST API
513
+ - [x] Mesh (Coinbase Rosetta) API
514
+ - [x] Bark block archive API
515
+ - [x] Mithril Bootstrap
516
+ - [x] Built-in Mithril client
517
+ - [x] Ledger state import (UTxOs, accounts, pools, DReps, epochs)
518
+ - [x] Block loading from ImmutableDB
204
519
 
205
520
  Additional planned features can be found in our issue tracker and project boards.
206
521
 
@@ -212,17 +527,117 @@ especially as there is functionality which has not yet been developed.
212
527
 
213
528
  ## Development / Building
214
529
 
215
- This requires Go 1.23 or better is installed. You also need `make`.
530
+ This requires Go 1.24 or later. You also need `make`.
216
531
 
217
532
  ```bash
218
- # Build
533
+ # Format, test, and build (default target)
219
534
  make
535
+
536
+ # Build only
537
+ make build
538
+
220
539
  # Run
221
540
  ./dingo
541
+
542
+ # Run without building a binary
543
+ go run ./cmd/dingo/
222
544
  ```
223
545
 
224
- You can also run the code without building a binary, first
546
+ ### Testing
225
547
 
226
548
  ```bash
227
- go run ./cmd/dingo/
549
+ make test # All tests with race detection
550
+ go test -v -race -run TestName ./package/ # Single test
551
+ make bench # Benchmarks
552
+ ```
553
+
554
+ ### Profiling
555
+
556
+ ```bash
557
+ # Load testdata with CPU and memory profiling
558
+ make test-load-profile
559
+
560
+ # Analyze
561
+ go tool pprof cpu.prof
562
+ go tool pprof mem.prof
228
563
  ```
564
+
565
+ ## DevNet
566
+
567
+ The DevNet runs a private Cardano network with Dingo and `cardano-node` producing blocks side by side. It validates that Dingo forges blocks, maintains consensus, and interoperates with the reference node.
568
+
569
+ ### Architecture
570
+
571
+ The DevNet uses Docker Compose to run 3 containers on a bridge network:
572
+
573
+ | Container | Role | Host Port |
574
+ |-----------|------|-----------|
575
+ | `dingo-producer` | Dingo block producer (pool 1) | 3010 |
576
+ | `cardano-producer` | cardano-node block producer (pool 2) | 3011 |
577
+ | `cardano-relay` | Relay node (no block production) | 3012 |
578
+
579
+ A `configurator` init container generates fresh pool keys and genesis files before nodes start.
580
+
581
+ ### Prerequisites
582
+
583
+ - Docker with the Compose plugin (`docker compose`)
584
+ - Go 1.24+
585
+
586
+ ### Running the Automated Tests
587
+
588
+ The test suite builds the Dingo Docker image, starts all containers, waits for health checks, and runs Go integration tests tagged with `//go:build devnet`:
589
+
590
+ ```bash
591
+ cd internal/test/devnet/
592
+
593
+ # Run all devnet tests
594
+ ./run-tests.sh
595
+
596
+ # Run a specific test
597
+ ./run-tests.sh -run TestBasicBlockForging
598
+
599
+ # Keep containers running after tests pass (for inspection)
600
+ ./run-tests.sh --keep-up
601
+ ```
602
+
603
+ Override host ports if needed:
604
+
605
+ ```bash
606
+ DEVNET_DINGO_PORT=4010 DEVNET_CARDANO_PORT=4011 DEVNET_RELAY_PORT=4012 ./run-tests.sh
607
+ ```
608
+
609
+ ### Running the DevNet Manually
610
+
611
+ For longer-running manual tests (soak testing, observing behavior over multiple epochs, debugging):
612
+
613
+ ```bash
614
+ cd internal/test/devnet/
615
+
616
+ # Start all containers
617
+ ./start.sh
618
+
619
+ # Watch logs
620
+ docker compose -f docker-compose.yml logs -f
621
+
622
+ # Watch a specific node
623
+ docker compose -f docker-compose.yml logs -f dingo-producer
624
+
625
+ # Stop and clean up
626
+ ./stop.sh
627
+ ```
628
+
629
+ Containers remain running until you stop them. The DevNet parameters (in `testnet.yaml`) use 1-second slots and 1500-slot epochs (~25 minutes per epoch), so you can observe epoch transitions, leader election, and stake snapshot rotation relatively quickly.
630
+
631
+ ### Local DevNet (Without Docker)
632
+
633
+ For quick iteration without Docker, `devmode.sh` runs Dingo directly against a local devnet genesis. It resets state and updates genesis timestamps on each run:
634
+
635
+ ```bash
636
+ # Run in devnet mode
637
+ ./devmode.sh
638
+
639
+ # With debug logging
640
+ DEBUG=true ./devmode.sh
641
+ ```
642
+
643
+ This stores state in `.devnet/` and uses genesis configs from `config/cardano/devnet/`. It runs a single Dingo node (no cardano-node counterpart), which is useful for testing startup, epoch transitions, and block production in isolation.