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.
make # fmt, test, build
make test # tests with -race
go test -v -race -run TestName ./path/to/pkg/
golangci-lint run ./...
nilaway ./...
modernize ./...
make import-boundaries
make golines
- No
time.Sleep()for sync — useinternal/test/testutil/(WaitForCondition,RequireReceive,context.WithTimeout). - Integration tests:
internal/integration/+database/immutable/testdata/(real blocks, slots 0–1.3M). - 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. - DevNet end-to-end (
internal/test/devnet/run-tests.sh): validate any change touching consensus, block production, header/VRF/KES/OpCert verification, chain selection, mempool, tx submission, NtN/NtC protocols, epoch boundaries, or nonce computation. Brings up Dingo + cardano-node side by side withtxpumpdriving the mempool, so it catches divergence from the reference implementation that unit tests miss. Conformance tests ininternal/test/conformance/are still mandatory after every change — DevNet is the additional bar for consensus-affecting work.
- Treat
DATABASE.mdandARCHITECTURE.mdas part of the change bar, like tests. Before finishing any code change, decide whether either document needs an update; update it in the same change when it does. - Update
DATABASE.mdfor any change to GORM models, migrated tables, table relationships, SQL query/API surfaces inmetadata.MetadataStore, blob-store key layout, CBOR/offset encodings, storage plugins, pruning/tombstone behavior, or anything external Postgres/MySQL/SQLite/blob users rely on. - Update
ARCHITECTURE.mdfor any change to component responsibilities, package boundaries, startup/composition, EventBus topics/payloads, plugin interfaces, lifecycle/concurrency behavior, or cross-component flows among ledger, database, mempool, networking, API, and node wiring. - In final responses, report documentation status the same way tests are reported: either list the docs updated or explicitly state that
DATABASE.md/ARCHITECTURE.mdwere checked and not affected.
- 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. - CBOR offsets: UTxOs/txs stored as 52-byte refs (magic
"DOFF"+ slot + hash + offset + length), resolved byTieredCborCache(hot → block LRU → cold extract). Seedatabase/cbor_offset.go. - Cert ordering:
Order("added_slot DESC, block_index DESC, cert_index DESC")—cert_indexresets per tx, soblock_indexis required to disambiguate across txs in the same block. - Rollbacks: delivered on
chain.updateas achain.ChainRollbackEventpayload (no separatechain.rollbacktopic); also subscribe tochain.fork_detectedfor fork metrics. CheckTransactionEvent.Rollbackfor undo. - Stake snapshots: mark/set/go rotation at epoch boundaries (Praos).
LedgerView.GetStakeDistribution(epoch)for leader election. Per-pool stake inPoolStakeSnapshot; aggregates inEpochSummary. - Plugins (
database/plugin/): blob =badger|gcs|s3; metadata =sqlite|mysql|postgres.
- Composition belongs in
node.go, root-package helpers,cmd/dingo, orinternal/node; do not make domain packages start, stop, or configure unrelated subsystems. - Use EventBus for async notifications only. For synchronous state reads, inject narrow interfaces or callbacks through constructors instead of importing a sibling package just to call one method.
- Keep dependency direction stable:
database/and storage plugins must not import ledger, mempool, networking, node, or API packages;connmanager/must not know Ouroboros or ledger semantics;chainselection/must not validate blocks or mutate ledger state. - Ledger owns validation, rollback repair, nonce/epoch logic, and ledger queries. It should not directly trigger connection-manager or peer-governance actions; emit a neutral event/callback and let node/network wiring translate it.
- Peer governance policy types should not leak into ledger data extraction. Put adapters at the composition boundary or behind neutral DTOs/interfaces.
- API packages should expose server behavior through package-local interfaces. Keep concrete adapters to
ledger,database, andmempoolnarrow, and require an explicit architecture review before adding new root-level API packages. - Tests may use
internal/test/testutil, but production packages must not importinternal/testor duplicate fixtures that belong inouroboros-mock.
| Event | Meaning |
|---|---|
chain.update |
block added |
chain.fork_detected |
fork |
chainselection.chain_switch |
active peer changed |
epoch.transition |
epoch boundary — triggers stake snapshot |
mempool.add_tx / mempool.remove_tx |
tx lifecycle |
connmanager.conn_closed |
connection closed |
peergov.peer_churn |
peer rotation |
Priority: CLI > env > YAML > defaults. Key env vars: CARDANO_NETWORK, CARDANO_DATABASE_PATH, DINGO_DATABASE_BLOB_PLUGIN, DINGO_DATABASE_METADATA_PLUGIN.