-
Notifications
You must be signed in to change notification settings - Fork 2
Getting Started for Developers
This guide covers everything you need to start contributing to Dugite.
-
Rust — latest stable toolchain, edition 2021. Install via rustup. The repository does not pin a toolchain file; CI builds with
dtolnay/rust-toolchain@stable, sorustup update stablekeeps you aligned. -
protoc(Protocol Buffers compiler) — required.dugite-rpc'sbuild.rsrunstonic-prost-build→prost-build, which shells out toprotoc. Without it the workspace does not build.- Debian/Ubuntu:
sudo apt-get install -y protobuf-compiler libprotobuf-dev - macOS:
brew install protobuf -
libprotobuf-devsupplies the well-knowngoogle/protobuf/*.protoincludes. GitHub's Ubuntu runners already have them; a clean Debian base does not (see theDockerfile).
- Debian/Ubuntu:
-
just— the task runner that wraps every common workflow.just --listshows all recipes. -
cargo-nextest— the test runner used by CI and byjust test. Install withcargo install cargo-nextest --locked. - Git, ~8 GB RAM to build and run the test suite, and Linux or macOS (Windows is untested).
Beyond protoc, no system libraries are needed: block storage is append-only chunk files and the UTxO set uses dugite-lsm, a pure-Rust LSM tree. On Linux, dugite-storage (re-exported by dugite-node) offers an optional io-uring feature that swaps the memmap chunk reader for a kernel io_uring backend.
git clone git@github.com:michaeljfazio/dugite.git
cd dugite
# Release build of every workspace target
just build
# Equivalent cargo invocations
cargo build --release --all-targets # what `just build` runs
cargo build --all-targets # debug build
cargo build --release # binaries only, fastest path to a nodejust test # cargo nextest run --workspace (matches CI)
just test-doc # cargo test --doc (nextest cannot run doc tests)Narrower runs go straight through cargo:
cargo nextest run -p dugite-ledger # one crate
cargo nextest run -p dugite-ledger -E 'test(test_name)' # one testjust clippy # cargo clippy --all-targets -- -D warnings
just fmt-check # cargo fmt --all -- --check
just fmt # cargo fmt --all (apply)just check runs the complete CI gate in order — fmt-check, clippy, build, test, test-doc. Run it before every commit.
just checkDo not pipe
just checkintotail/head: the pipeline reports the exit status of the last command, so a failing gate looks green.
The workspace has 16 crates under crates/, plus xtask and two test-suite crates under tests/.
| Crate | Purpose |
|---|---|
dugite-primitives |
Core types: hashes, blocks, transactions, addresses, values, protocol parameters (all eras Byron–Conway) |
dugite-crypto |
Ed25519 keys, VRF (ECVRF-ED25519-SHA512-Elligator2), KES (Sum6Kes), text envelope format |
dugite-serialization |
In-house multi-era CBOR encoder/decoder (minicbor-based) |
dugite-uplc |
In-house UPLC CEK machine — 100% conformant; used by dugite-ledger for Phase-2 Plutus evaluation |
dugite-network |
Ouroboros mini-protocols (N2N/N2C), multiplexer, pipelined ChainSync client |
dugite-consensus |
Ouroboros Praos, chain selection, epoch transitions, VRF leader check |
dugite-ledger |
UTxO set (UTxO-HD), transaction validation (Phase-1/Phase-2), ledger state, certificates, rewards, governance |
dugite-mempool |
Thread-safe transaction mempool with input-conflict checking and TTL sweep |
dugite-lsm |
Pure-Rust LSM-tree engine backing the on-disk UTxO set (no workspace dependencies) |
dugite-storage |
ChainDB = ImmutableDB (append-only chunk files) + VolatileDB (in-memory). Owns the optional Linux io-uring chunk-read backend |
dugite-rpc |
Native UTxO RPC (gRPC) server built from vendored utxorpc protos. The only crate that depends on tonic/prost, so the gRPC stack stays out of the node's graph when RPC is off |
dugite-node |
Binary. The node: config, topology, pipelined sync, Mithril import, block forging, metrics, RPC adapter |
dugite-cli |
Binary. cardano-cli compatible CLI: 11 command groups, ~92 leaf subcommands, era-prefix aliases |
dugite-monitor |
Binary. Terminal monitoring dashboard (ratatui-based, polls the Prometheus endpoint) |
dugite-config |
Binary. Interactive TUI config editor: tree navigation, inline editing, type validation, search/filter, diff view, plus init/validate/get/set subcommands |
dugite-integration-tests |
End-to-end integration tests (test-only crate, no binary) |
Test-suite crates: tests/conformance (package dugite-conformance — upstream golden replay) and tests/golden (package dugite-golden-tests). xtask hosts repo automation such as cargo xtask download-upstream-fixtures.
Dependency flow (workspace edges only):
dugite-node ──► network, consensus, ledger, storage, mempool, rpc, uplc, serialization, crypto, primitives
dugite-cli ──► network, consensus, serialization, crypto, primitives
dugite-rpc ──► mempool, serialization, primitives
dugite-network / dugite-storage ──► consensus, serialization, crypto, primitives
dugite-mempool ──► ledger, crypto, primitives
dugite-ledger ──► lsm, uplc, serialization, crypto, primitives
dugite-consensus / dugite-uplc ──► serialization, crypto*, primitives (*consensus only)
dugite-serialization / dugite-crypto ──► primitives
dugite-monitor, dugite-lsm, dugite-primitives ──► (no workspace dependencies)
dugite-config depends on dugite-node only as a dev-dependency (it validates against the node's real config schema).
If you are new to the codebase, start with these:
-
CLAUDE.md(repo root) — architecture overview, build commands, key patterns, per-release notes -
crates/dugite-node/src/main.rs— entry point, CLI subcommands (run,mithril-import,db,dump-snapshot,verify-ledger-snapshot,snapshot-convert), startup -
crates/dugite-node/src/node/mod.rsandnode/sync.rs— node lifecycle and the pipelined sync loop -
crates/dugite-ledger/src/lib.rs— ledger state and block application -
crates/dugite-storage/src/chain_db.rs— ChainDB (ImmutableDB + VolatileDB) -
crates/dugite-network/src/lib.rs— mini-protocols and the multiplexer -
crates/dugite-consensus/src/lib.rs— consensus engine and epoch transitions -
crates/dugite-primitives/src/lib.rs— core type definitions
The fastest way to a running node is a Mithril snapshot import followed by a relay run. Both are one-liners:
just build # cargo build --release --all-targets
just mithril-import preview # ./scripts/mithril/import.sh preview
just run-relay preview # ./scripts/run/relay-preview.shmithril-import, run-relay, and run-bp all take mainnet | preview | preprod.
The underlying commands, if you prefer to drive the binary directly:
./target/release/dugite-node mithril-import \
--network-magic 2 \
--database-path ./db-preview
./target/release/dugite-node run \
--config config/preview/config.json \
--topology config/preview/topology.json \
--database-path ./db-preview \
--socket-path ./node.sock \
--host-addr 0.0.0.0 --port 3001| Network | Magic | Config directory |
|---|---|---|
| Mainnet | 764824073 |
config/mainnet/ |
| Preview | 2 |
config/preview/ |
| Preprod | 1 |
config/preprod/ |
Each directory holds config.json, topology.json, and the Byron, Shelley, Alonzo, and Conway genesis files, with relative paths — no rewriting needed.
The Prometheus endpoint port is resolved with this precedence: --no-metrics (0, disabled) → --metrics-port → TurnOnLogMetrics: false in the config (0) → MetricsPort in the config → built-in default 12796. The shipped configs set it explicitly, so a stock run uses:
| Config | MetricsPort |
|---|---|
config/preview/config.json |
12796 |
config/preprod/config.json |
12799 |
config/mainnet/config.json |
12800 |
Tail whichever port you are on with just watch-metrics <port> (the recipe's own default argument is 12798, cardano-node's port — pass yours explicitly). just monitor-start brings up a local Prometheus + Grafana stack in Docker.
A three-node loopback devnet (dugite-bp, dugite-relay, cardano-node-bp) lives under testnet/local-devnet/:
just devnet-setup # render configs, generate keys, fetch reference binaries
just devnet-run # start all three nodes
just devnet-soak # 30-minute soak
just devnet-verify # check the evidence from the last run
just devnet-stop
just devnet-validate-smoke # single boot, ~5 min — the PR gate for core crates
just devnet-validate-extended # 3 rounds, ~75 min — the release gateReports are written to reports/devnet-validate/. Note that the tx-zoo/09-cli-parity suite runs cardano-cli against both sockets and diffs the answers: it measures dugite-node's LSQ responses, never dugite-cli. A failure on both sides is a harness bug.
Upstream artefacts are republished as a pinned dugite release and consumed as fixtures.
just download-upstream-fixtures # all areas, at the tag in tests/conformance/upstream/manifest.toml
just download-upstream-fixtures-area plutus
just test-conformance # UPLC corpus + every upstream golden suite
just test-conformance-ledger-rules # one area (per-area recipes exist for each)Seven areas: ouroboros-consensus, cardano-ledger, cardano-node, plutus (999 UPLC vectors), ledger-rules (ImpSpec CBOR vectors), cardano-base (VRF vectors), mithril. Per-area recipes report "N skipped" for the tests they filtered out — that is not a coverage gap; use the unfiltered just test-conformance for a real zero-skip run.
- Assess — evaluate the current state and pick the highest-impact gap or bug
- Implement — keep changes focused and reviewable
-
Test —
just test(andjust test-doc), zero failures -
Verify —
just clippyandjust fmt-check, orjust checkfor the whole gate - Commit — descriptive message, explicit filenames staged
- Repeat
- Zero compiler warnings (
RUSTFLAGS="-D warnings") - Clippy clean at
-D warnings - All tests passing
- Code formatted
- CI green before merge
- Stage explicit filenames — no
git add -A/git commit -a. The repo ships.githooks/pre-commit, which warns when staged paths span more than two crates; enable it withgit config core.hooksPath .githooks, and setDUGITE_PRECOMMIT_STRICT=1to make the warning fatal.
Runtime knobs (node):
| Variable | Default | Description |
|---|---|---|
DUGITE_PIPELINE_DEPTH |
300 |
ChainSync pipeline high-water mark; refill happens at ~67% |
DUGITE_FETCHED_BLOCKS_CAP |
4096 |
In-flight fetched-block channel capacity; lower it to cap peak memory |
DUGITE_VOLATILE_RETAIN |
10000 |
Blocks retained in the VolatileDB live set |
DUGITE_SHUTDOWN_DEADLINE_SECS |
90 |
Graceful-shutdown deadline; a second signal forces exit |
DUGITE_TRUSTED_CATCHUP |
unset | Set to 1 to opt out of full validation during catch-up |
DUGITE_BLOCKFETCH_MAX_RANGE |
config | Overrides the per-batch BlockFetch range cap at runtime |
RUST_LOG |
info |
Log filter (trace, debug, info, warn, error); overrides --log-level
|
Test and tooling knobs:
| Variable | Description |
|---|---|
DUGITE_REQUIRE_UPSTREAM=1 |
Make upstream conformance tests fail rather than skip when fixtures are missing (CI sets this) |
DUGITE_UPSTREAM_FIXTURES_DIR |
Override the fixture lookup root (default tests/conformance/upstream/fixtures/) |
DUGITE_DUAL_DECODE |
panic or dump — cross-check the in-house decoder against the shadow decoder (just dual-decode-smoke, just dual-decode-soak) |
DUGITE_PRECOMMIT_STRICT=1 |
Make the multi-crate pre-commit tripwire fatal |
The node also honours a long tail of diagnostic dumps (DUGITE_EPOCH_STATE_DUMP, DUGITE_PHASE2_DUMP_DIR, DUGITE_REWARD_DEBUG_DUMP, …). Grep crates/ for DUGITE_ to see the full set.
- Architecture Decision Records — key design decisions and rationale
- Protocol Compliance — current feature compliance status
- Performance Baselines — measured performance numbers
- Known Issues — current bugs and limitations
- Published Documentation — mdBook documentation
-
CONTRIBUTING.md— contribution workflow