Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions .envrc
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export APPEND_ARGS="--allow-private-ip --pool-limit 10 --trie-cache-size 0 --pro


# Validator Values:
if [ ! -f node.privatekey ]; then
if [ ! -f midnight-node.privatekey ]; then
# generate node key like this:
DOCKER_DEFAULT_PLATFORM=linux/amd64 docker run --rm -it docker.io/parity/subkey:latest generate-node-key | sed -n '2p' > midnight-node.privatekey
# Use the second line of output for NODE_KEY (that's what sed -n '2p' does)
Expand All @@ -50,6 +50,24 @@ export NODE_KEY="$(cat ./midnight-node.privatekey)"
# Cardano chain config:
#
export CARDANO_NETWORK=preview
export CARDANO_IMAGE="ghcr.io/intersectmbo/cardano-node:10.5.3"
export CARDANO_IMAGE="ghcr.io/intersectmbo/cardano-node:10.6.2"
export CARDANO_DATA_DIR=./cardano-data
export CARDANO_CONFIG_DIR=./cardano-config/${CARDANO_NETWORK}

#
# Mithril (Fast Cardano Sync):
#
export MITHRIL_IMAGE="ghcr.io/input-output-hk/mithril-client:latest"
if [ "$CARDANO_NETWORK" = "preview" ]; then
export MITHRIL_AGGREGATOR_ENDPOINT="https://aggregator.pre-release-preview.api.mithril.network/aggregator"
export MITHRIL_GENESIS_VERIFICATION_KEY="5b3132372c37332c3132342c3136312c362c3133372c3133312c3231332c3230372c3131372c3139382c38352c3137362c3139392c3136322c3234312c36382c3132332c3131392c3134352c31332c3233322c3234332c34392c3232392c322c3234392c3230352c3230352c33392c3233352c34345d"
export MITHRIL_ANCILLARY_VERIFICATION_KEY="5b3138392c3139322c3231362c3135302c3131342c3231362c3233372c3231302c34352c31382c32312c3139362c3230382c3234362c3134362c322c3235322c3234332c3235312c3139372c32382c3135372c3230342c3134352c33302c31342c3232382c3136382c3132392c38332c3133362c33365d"
elif [ "$CARDANO_NETWORK" = "preprod" ]; then
export MITHRIL_AGGREGATOR_ENDPOINT="https://aggregator.pre-release-preprod.api.mithril.network/aggregator"
export MITHRIL_GENESIS_VERIFICATION_KEY="5b3132372c37332c3132342c3136312c362c3133372c3133312c3231332c3230372c3131372c3139382c38352c3137362c3139392c3136322c3234312c36382c3132332c3131392c3134352c31332c3233322c3234332c34392c3232392c322c3234392c3230352c3230352c33392c3233352c34345d"
export MITHRIL_ANCILLARY_VERIFICATION_KEY="5b3138392c3139322c3231362c3135302c3131342c3231362c3233372c3231302c34352c31382c32312c3139362c3230382c3234362c3134362c322c3235322c3234332c3235312c3139372c32382c3135372c3230342c3134352c33302c31342c3232382c3136382c3132392c38332c3133362c33365d"
elif [ "$CARDANO_NETWORK" = "mainnet" ]; then
export MITHRIL_AGGREGATOR_ENDPOINT="https://aggregator.release-mainnet.api.mithril.network/aggregator"
export MITHRIL_GENESIS_VERIFICATION_KEY="5b3139312c36362c3134302c3138352c3133382c31312c3233372c3230372c3235302c3134342c32372c322c3138382c33302c31322c38312c3135352c3230342c31302c3137392c37352c3233322c3133382c3139362c3231372c352c31342c32302c35372c37392c33392c3137365d"
export MITHRIL_ANCILLARY_VERIFICATION_KEY="5b32332c37312c39362c3133332c34372c3235332c3232362c3133362c3233352c35372c3136342c3130362c3138362c322c32312c32392c3132302c3136332c38392c3132312c3137372c3133382c3230382c3133382c3231342c39392c35382c32322c302c35382c332c36395d"
fi
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,32 @@ rm -R ./cardano-data
docker volume rm midnight-node-docker_midnight-data-testnet
```

### Fast Sync with Mithril (Cardano)

Syncing a Cardano node from scratch can take several days. To speed this up, you can use **Mithril** to download a verified snapshot of the blockchain. This usually takes between 30 minutes and a couple of hours.

The restoration script is fully automated and will:
- Download the latest immutable blocks (approx 14GB).
- **Automatically inject the latest ledger state** (ancillary files) to bypass the lengthy block replay phase.
- Configure the correct `protocolMagicId` for the network.

#### Prerequisites
Ensure you have the following tools installed:
- `jq`, `wget`, `zstd`, `curl`
- `docker` and `docker compose`

#### Instructions
1. Ensure `direnv allow` has been run so the Mithril configuration is loaded (or source `.envrc`).
2. Ensure you are starting from a clean state (no `./cardano-data/db` directory).
3. Run the restoration script:
```sh
./restore-cardano-snapshot.sh
```
4. Once complete, start your nodes as usual:
```sh
docker compose -f ./compose-partner-chains.yml up -d cardano-node
```

#### Env vars not setup

If you get warnings like this then likely `direnv` is not setup or `direnv allow` has not been run:
Expand Down
105 changes: 105 additions & 0 deletions restore-cardano-snapshot.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#!/usr/bin/env bash
set -euo pipefail

# This file is part of https://github.com/midnightntwrk/midnight-node-docker
# Copyright (C) 2025 Midnight Foundation
# SPDX-License-Identifier: Apache-2.0

# Load environment if direnv is not used
if [ -z "${MITHRIL_IMAGE:-}" ]; then
if [ -f .envrc ]; then
echo "Loading environment from .envrc..."
source .envrc
fi
fi

# Fallback defaults if still not set
NETWORK=${CARDANO_NETWORK:-preview}
DATA_DIR=${CARDANO_DATA_DIR:-./cardano-data}
MITHRIL_IMAGE=${MITHRIL_IMAGE:-ghcr.io/input-output-hk/mithril-client:latest}

echo "─── Cardano snapshot restoration (Mithril) ───"
echo "Network: $NETWORK"
echo "Data directory: $DATA_DIR"

if [ ! -d "$DATA_DIR" ]; then
echo "Creating data directory $DATA_DIR..."
mkdir -p "$DATA_DIR"
fi

# Check if DB is already populated
if [ -d "$DATA_DIR/db" ] && [ "$(ls -A "$DATA_DIR/db" 2>/dev/null)" ]; then
echo "Error: $DATA_DIR/db is not empty."
echo "If you want to restore a fresh snapshot, please remove the existing database first:"
echo " rm -rf $DATA_DIR/db"
exit 1
fi

# Ensure we have the necessary Mithril variables
if [ -z "${MITHRIL_AGGREGATOR_ENDPOINT:-}" ] || [ -z "${MITHRIL_GENESIS_VERIFICATION_KEY:-}" ]; then
echo "Error: MITHRIL_AGGREGATOR_ENDPOINT or MITHRIL_GENESIS_VERIFICATION_KEY not set."
echo "Please ensure you have run 'direnv allow' or populated these variables in .envrc"
exit 1
fi

echo "Pulling Mithril client image ($MITHRIL_IMAGE)..."
docker pull "$MITHRIL_IMAGE"

echo "Downloading latest snapshot for $NETWORK..."

# Check for required tools
for tool in jq wget zstd curl; do
if ! command -v "$tool" &> /dev/null; then
echo "Error: $tool is not installed. Please install it first."
exit 1
fi
done

# Execute the main restoration
docker run --rm \
-e AGGREGATOR_ENDPOINT="$MITHRIL_AGGREGATOR_ENDPOINT" \
-e GENESIS_VERIFICATION_KEY="$MITHRIL_GENESIS_VERIFICATION_KEY" \
-e ANCILLARY_VERIFICATION_KEY="$MITHRIL_ANCILLARY_VERIFICATION_KEY" \
-v "$(pwd)/$DATA_DIR:/data" \
"$MITHRIL_IMAGE" \
cardano-db download latest --download-dir /data --include-ancillary

echo "─── Post-Restoration Fixes ───"

# Fix 1: Ensure protocolMagicId exists (required by cardano-node to identify the network)
if [ "$NETWORK" == "preview" ]; then MAGIC=2; elif [ "$NETWORK" == "preprod" ]; then MAGIC=1; else MAGIC=764824073; fi
echo -n "$MAGIC" > "$DATA_DIR/db/protocolMagicId"
echo "✅ Created protocolMagicId: $MAGIC"

# Fix 2: Manual Ledger Injection (Mithril often skips these or they fail to extract)
# We detect if ledger is empty or small and inject if necessary.
if [ -d "$DATA_DIR/db/ledger" ] && [ "$(ls -A "$DATA_DIR/db/ledger" 2>/dev/null)" ]; then
echo "✅ Ledger state found."
else
echo "⚠️ Ledger state missing. Injecting manual ancillary snapshot to bypass block replay..."
# We fetch the ancillary URL dynamically from the aggregator for the 'latest' snapshot
DIGEST=$(docker run --rm -e AGGREGATOR_ENDPOINT="$MITHRIL_AGGREGATOR_ENDPOINT" "$MITHRIL_IMAGE" cardano-db snapshot list --json | jq -r '.[0].hash')
ANCILLARY_URL=$(curl -s "$MITHRIL_AGGREGATOR_ENDPOINT/artifact/cardano-database/$DIGEST" | jq -r '.ancillary.locations[0].uri')

if [ "$ANCILLARY_URL" != "null" ]; then
echo "Downloading ancillary files from $ANCILLARY_URL..."
wget -q -O ancillary.tar.zst "$ANCILLARY_URL"
zstd -d -q ancillary.tar.zst
tar -xf ancillary.tar -C "$DATA_DIR/db/"
rm -f ancillary.tar ancillary.tar.zst
echo "✅ Ledger injection complete."
else
echo "❌ Could not find ancillary URL in aggregator metadata. Node will perform fallback replay."
fi
fi

# Fix 3: Permissions (ensure Docker can read the files)
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
# On Linux, we might need to chown to 1000 (standard for cardano-node image)
sudo chown -R 1000:1000 "$DATA_DIR/db" 2>/dev/null || true
fi
chmod -R 777 "$DATA_DIR/db" 2>/dev/null || true

echo "─── Fast Sync Complete ───"
echo "You can now start your Cardano node:"
echo " docker compose -f compose-partner-chains.yml up -d cardano-node"