This guide covers best practices and tribal knowledge for working effectively on midnight-node.
General Rule: Use cargo commands for iterative development, Earthly for specific tasks only.
- Day-to-day development
- Iterative compilation during coding
- Running tests
- Code formatting and linting
cargo check # Type checking
cargo test # Run tests
cargo clippy # Linting
cargo fmt # Format code
cargo build # Build debug binary
cargo build --release # Build release binaryWhy cargo? Earthly check will recompile only the code in the repo - all the deps are precompiled so it's not very slow, just slower. Cargo's incremental compilation is much faster for iterative development.
- Building Docker images
- Generating metadata
- Rebuilding genesis
- Running CI-equivalent checks locally
- Tasks requiring containerized environments
earthly -P +rebuild-metadata # Update runtime metadata
earthly -P +rebuild-genesis # Regenerate genesis state
earthly +build # Build in containerized environment
earthly +node-image # Build node Docker image
earthly doc # List all available targetsWhy Earthly? Ensures reproducible builds in clean containerized environments, matches CI behavior exactly.
Step 1: Install Prerequisites
Choose one:
# Option A: Manual installation
# Install rustup and earthly following docs/rust-setup.md
# Option B: Use Nix (provides everything automatically)
nix developStep 2: Load Environment Variables
Choose one:
# Option A: Using direnv (automatic)
cd /path/to/midnight-node # direnv loads .envrc automatically
# Option B: Manual
source .envrcNote: If you chose Nix in Step 1, you still need to choose an environment loading method from Step 2.
# Run all tests
cargo test
# Run specific test
cargo test test_name
# Run tests with output
cargo test -- --nocapture
# Run integration tests only
cargo test --test integration_test_name# Before committing, run these checks
cargo clippy # Lints and warnings (includes type checking)
cargo fmt # Format code
cargo test # Run testsWhen upgrading the midnight-ledger dependency:
# Edit Cargo.toml files with new ledger version
# Then check for compilation errors and update lock file
cargo checkCommon issues during ledger upgrades:
LedgerState::apply_intent()signature changes (e.g., new parameters added)- New trait requirements on types (e.g.,
impl Serialize for RuntimeTransaction) - Changed return types (e.g.,
Result<T, E>where error typeEhas changed) - New fields in structs that need initialization (e.g.,
TransactionContextgains new fields) - Method renames or moves to different modules (e.g., functions moving from
ledger::apitoledger::core)
earthly -P +rebuild-metadataThis regenerates the runtime metadata that clients use to interact with the node. This needs to be re-run when:
- Pallet storage items change
- Extrinsic (callable functions) signatures change
- Runtime APIs are added or modified
- Custom types used in the runtime interface change
earthly -P +rebuild-genesisRequired when:
- Runtime storage format changes
- New pallets are added
- Genesis configuration changes
The output of this will be a chain spec file which contains the hex of the genesis.
cargo test # Unit and integration tests
earthly +test # CI-equivalent tests (slow)Maintain a local checkout of the midnight-ledger repository:
git clone https://github.com/midnightntwrk/midnight-ledgerWhy? When you encounter ledger-related errors, you can search the source code directly:
cd midnight-ledger
# Search for error messages or types
rg "error message text"
rg "LedgerState"The LedgerState implementation contains most of the critical logic. Understanding this code is essential for working on ledger-adjacent parts of the node.
Error in transaction processing:
- Check the error message
- Search midnight-ledger for the error text
- Review LedgerState implementation
- Check recent changes in ledger version
State inconsistency:
- Verify genesis configuration
- Check if metadata needs rebuilding
- Review recent runtime changes
Build failures after ledger upgrade:
- Check Cargo.toml for correct version pinning
- Look for API changes in midnight-ledger changelog
- Search for the failing function/type in midnight-ledger source
# Build chain spec for local development
./target/release/midnight-node build-spec --disable-default-bootnode > chain-spec.json
# Convert to raw format
./target/release/midnight-node build-spec --chain chain-spec.json --raw > chain-spec-raw.json
# Start node with custom chain spec
./target/release/midnight-node --chain chain-spec-raw.json- undeployed/local - Local development, no AWS secrets required
- qanet - QA testing network, requires AWS secrets
- preview - Preview/staging network, requires AWS secrets
- testnet - Public testnet, requires AWS secrets
If you don't have AWS access:
- You can only work with the
undeployednetwork - Cannot rebuild genesis for deployed networks (qanet, preview, testnet)
- For genesis rebuilds requiring secrets, contact the node team
When you need genesis rebuilt with secrets:
- Open a PR with your changes
- Ask the node team in Slack: "Could someone with AWS access run
earthly -P +rebuild-genesisafter downloading the secrets?" - A team member with AWS access will handle it
See toolkit README for using the transaction generator to create test load.
# Runtime benchmarks (if enabled with runtime-benchmarks feature)
cargo build --release --features runtime-benchmarks
./target/release/midnight-node benchmark pallet --pallet pallet_nameNote: The hardfork testing process is currently incomplete. It was partially rewritten before the ledger v6 upgrade and never completed. Use the general upgrade testing approach documented in testing-upgrades.md instead.
| Task | Command |
|---|---|
| Daily development | cargo check, cargo test, cargo clippy |
| Update metadata | earthly -P +rebuild-metadata |
| Rebuild genesis | earthly -P +rebuild-genesis |
| Build Docker image | earthly +node-image |
| List Earthly targets | earthly doc |
| Start dev environment | nix develop or source .envrc |
| Run local node | CFG_PRESET=dev ./target/release/midnight-node |
- Use incremental builds: Always prefer cargo over Earthly during development
- Keep ledger source handy: Clone midnight-ledger locally for debugging
- Test before committing: Run
cargo check && cargo test && cargo clippy && cargo fmt - Use Nix or direnv: Don't manually manage environment variables
- Let CI handle complex builds: Don't run full Earthly builds locally unless necessary
- Ask for help with secrets: Don't try to work around AWS secret requirements