Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
d045acc
No pad hasher header (#327)
dastansam Nov 28, 2025
0123aeb
Verify header in the wormhole proof (#295)
dastansam Nov 29, 2025
44f30a2
Merge branch 'main' of github.com:Quantus-Network/chain into wormhole
dastansam Dec 12, 2025
cd916c2
Use canonical balances pallet and add support for assets in wormhole …
dastansam Dec 22, 2025
365eb94
Use `ToFelts` trait in the wormhole pallet (#347)
dastansam Jan 14, 2026
1de4987
Add ValidateUnsigned impl to wormhole (#353)
dastansam Jan 19, 2026
426041e
feat: aggregated proof verification in wormhole (#351)
dastansam Jan 19, 2026
ee4616a
check block hash in agg proof
illuzen Jan 19, 2026
44e406b
feat: quantized funding amounts (#354)
ethan-crypto Jan 19, 2026
4307308
Enforce miner wormhole address (#344)
illuzen Jan 19, 2026
bfac102
Merge branch 'testnet/planck' into wormhole
illuzen Jan 19, 2026
33c4e3e
update qp-poseidon version
illuzen Jan 19, 2026
c5956c7
Merge branch 'wormhole' of github.com:Quantus-Network/chain into worm…
illuzen Jan 19, 2026
d584746
made transfer count per-recipient
illuzen Jan 20, 2026
de5553a
feat: enable wormhole verifier tests (#356)
ethan-crypto Jan 20, 2026
40978d6
remove painful test, we sent it to quantus-cli
illuzen Jan 20, 2026
5df799f
burn half the volume fee
illuzen Jan 20, 2026
a837d44
fmt
illuzen Jan 20, 2026
86b7389
Merge branch 'wormhole' into testnet/planck
illuzen Feb 3, 2026
de0874e
use new plonky2-verifier crate
illuzen Feb 6, 2026
07fc6ea
fix: Remove no_random feature and patch plonky2 crates to use local v…
illuzen Feb 6, 2026
a6492aa
lock
illuzen Feb 9, 2026
427b21d
new agg logic
illuzen Feb 10, 2026
ecea17c
better logging of agg proof failure modes
illuzen Feb 11, 2026
24fee87
refresh bins
illuzen Feb 11, 2026
ad248c7
only one proof verified event necessary
illuzen Feb 11, 2026
e86b0d3
update to latest rusty crystals
illuzen Feb 11, 2026
615ddcc
no minimum, no single proof verification
illuzen Feb 11, 2026
0f9d207
lock
illuzen Feb 11, 2026
149f772
handle new derivation rules
illuzen Feb 12, 2026
3fe59cc
fmt
illuzen Feb 12, 2026
5970fd5
put wormhole transfer minimum back in, remove unused single-proof files
illuzen Feb 12, 2026
bc58efa
merge
illuzen Feb 12, 2026
0b388ae
better lock
illuzen Feb 12, 2026
6410a25
remove local plonky2 references
illuzen Feb 13, 2026
e9d6819
fix build.rs bin validation
illuzen Feb 14, 2026
9df520f
remove unused functions
illuzen Feb 15, 2026
7916bf5
format
illuzen Feb 15, 2026
da71707
no more local deps
illuzen Feb 15, 2026
effba83
missing dev accounts
illuzen Feb 15, 2026
6f75a97
clippy
illuzen Feb 15, 2026
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
347 changes: 217 additions & 130 deletions Cargo.lock

Large diffs are not rendered by default.

31 changes: 15 additions & 16 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ members = [
"client/network",
"miner-api",
"node",
"pallets/balances",
"pallets/mining-rewards",
"pallets/multisig",
"pallets/qpow",
Expand Down Expand Up @@ -75,7 +74,7 @@ lazy_static = { version = "1.5.0", default-features = false, features = [
"spin_no_std",
] }
libp2p = { version = "0.54.1" }
libp2p-identity = { git = "https://github.com/Quantus-Network/qp-libp2p-identity", tag = "v0.2.11_patch_qp_rusty_crystals_dilithium_2_0" }
libp2p-identity = { git = "https://github.com/Quantus-Network/qp-libp2p-identity", tag = "v0.2.11_patch_qp_rusty_crystals_dilithium_2_1" }
linked_hash_set = { version = "0.1.4" }
log = { version = "0.4.22", default-features = false }
memory-db = { version = "0.34.0", default-features = false }
Expand Down Expand Up @@ -130,7 +129,7 @@ wasm-timer = { version = "0.2.5" }
zeroize = { version = "1.7.0", default-features = false }

# Own dependencies
pallet-balances = { path = "./pallets/balances", default-features = false }
pallet-balances = { version = "42.0.0", default-features = false }
pallet-mining-rewards = { path = "./pallets/mining-rewards", default-features = false }
pallet-multisig = { path = "./pallets/multisig", default-features = false }
pallet-qpow = { path = "./pallets/qpow", default-features = false }
Expand All @@ -149,18 +148,19 @@ sp-consensus-pow = { path = "./primitives/consensus/pow", default-features = fal
sp-consensus-qpow = { path = "./primitives/consensus/qpow", default-features = false }

# Quantus network dependencies
qp-poseidon = { version = "1.0.1", default-features = false }
qp-poseidon-core = { version = "1.0.1", default-features = false, features = ["p3"] }
qp-rusty-crystals-dilithium = { version = "2.0.0", default-features = false }
qp-rusty-crystals-hdwallet = { version = "1.0.0" }
qp-wormhole-circuit = { version = "0.1.2", default-features = false }
qp-wormhole-circuit-builder = { version = "0.1.2", default-features = false }
qp-wormhole-verifier = { version = "0.1.2", default-features = false, features = [
"no_random",
] }
qp-zk-circuits-common = { version = "0.1.2", default-features = false, features = [
"no_random",
qp-plonky2 = { version = "1.1.3", default-features = false }
qp-poseidon = { version = "1.0.7", default-features = false }
qp-poseidon-core = { version = "1.0.7", package = "qp-poseidon-core", default-features = false, features = [
"p2",
"p3",
] }
qp-rusty-crystals-dilithium = { version = "2.1.0", default-features = false }
qp-rusty-crystals-hdwallet = { version = "1.3.0" }
qp-wormhole-circuit = { version = "1.0.5", default-features = false }
qp-wormhole-circuit-builder = { version = "1.0.5", default-features = false }
qp-wormhole-prover = { version = "1.0.5", default-features = false }
qp-wormhole-verifier = { version = "1.0.5", default-features = false }
qp-zk-circuits-common = { version = "1.0.5", default-features = false }

# polkadot-sdk dependencies
frame-benchmarking = { version = "41.0.0", default-features = false }
Expand Down Expand Up @@ -233,14 +233,13 @@ substrate-test-utils = { version = "3.0.0", default-features = false }
substrate-wasm-builder = { version = "27.0.0", default-features = false }

[patch.crates-io]
libp2p-identity = { git = "https://github.com/Quantus-Network/qp-libp2p-identity", tag = "v0.2.11_patch_qp_rusty_crystals_dilithium_2_0" }
libp2p-identity = { git = "https://github.com/Quantus-Network/qp-libp2p-identity", tag = "v0.2.11_patch_qp_rusty_crystals_dilithium_2_1" }
libp2p-noise = { git = "https://github.com/Quantus-Network/qp-libp2p-noise", tag = "v0.45.10" }
sc-cli = { path = "./client/cli" }
sc-network = { path = "client/network" }
sp-state-machine = { path = "./primitives/state-machine" }
sp-trie = { path = "./primitives/trie" }


[profile.release]
opt-level = 3
panic = "unwind"
Expand Down
124 changes: 93 additions & 31 deletions MINING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@

Get started mining on the Quantus Network testnet in minutes.

## Important: Wormhole Address System

**⚠️ Mining rewards are automatically sent to wormhole addresses derived from your preimage.**

- You provide a 32-byte preimage when starting mining
- The system derives your wormhole address using Poseidon hashing
- All mining rewards are sent to this derived wormhole address
- This ensures all miners use privacy-preserving wormhole addresses

## System Requirements

### Minimum Requirements
Expand Down Expand Up @@ -32,17 +41,17 @@ If you prefer manual installation or the script doesn't work for your system:
./quantus-node key generate-node-key --file ~/.quantus/node_key.p2p
```

3. **Generate Rewards Address**
3. **Generate Wormhole Address & Preimage**

```bash
./quantus-node key quantus
./quantus-node key quantus --scheme wormhole
```

The address is in the output like this:
```sh
...
Address: qzpjg55HuN2vLdQerpZwhsGfRn6b4pc8uh4bdEgsYbJNeu8rn
...
```

This generates a wormhole key pair and shows:
- `Address`: Your wormhole address (where rewards will be sent)
- `inner_hash`: Your 32-byte preimage (use this for mining)

**Save the preimage** - you'll need it for the `--rewards-address` parameter.

4. **Run the node (Dirac testnet)**

Expand All @@ -52,10 +61,12 @@ Minimal command - see --help for many more options
--validator \
--chain dirac \
--node-key-file ~/.quantus/node_key.p2p \
--rewards-address <COPIED_REWARDS_ADDRESS> \
--rewards-preimage <YOUR_PREIMAGE_FROM_STEP_3> \
--max-blocks-per-request 64 \
--sync full
```

**Note:** Use the `inner_hash` from step 3 as your `--rewards-preimage`. The node will derive your wormhole address and log it on startup.
### Docker Installation

For users who prefer containerized deployment or have only Docker installed:
Expand Down Expand Up @@ -92,23 +103,20 @@ docker run --rm --platform linux/amd64 \
Replace `quantus-node:v0.0.4` with your desired image (e.g., `ghcr.io/quantus-network/quantus-node:latest`).
This command saves `node_key.p2p` into your local `./quantus_node_data` directory.

**Step 3: Generate and Save Your Rewards Address**
**Step 3: Generate Your Wormhole Address**

Run the following command to generate your unique rewards address:
```bash
# If on Apple Silicon, you may need to add --platform linux/amd64
docker run --rm ghcr.io/quantus-network/quantus-node:latest key quantus
docker run --rm ghcr.io/quantus-network/quantus-node:latest key quantus --scheme wormhole
```
Replace `quantus-node:v0.0.4` with your desired image.
This command will display your secret phrase, public key, address, and seed.
**Important: Securely back up your secret phrase!**
Next, **copy the displayed `Address`.

This generates a wormhole key pair. Save the `inner_hash` value - this is your preimage for mining.

**Step 4: Run the Validator Node**

Now, run the Docker container with all the necessary parameters:
```bash
# If on Apple Silicon, you may need to add --platform linux/amd64
# Replace YOUR_PREIMAGE with the inner_hash from step 3
docker run -d \
--name quantus-node \
--restart unless-stopped \
Expand All @@ -120,7 +128,7 @@ docker run -d \
--base-path /var/lib/quantus \
--chain dirac \
--node-key-file /var/lib/quantus/node_key.p2p \
--rewards-address <COPIED_REWARDS_ADDRESS>
--rewards-preimage <YOUR_PREIMAGE>
```

*Note for Apple Silicon (M1/M2/M3) users:* As mentioned above, if you are using an `amd64` based Docker image on an ARM-based Mac, you will likely need to add the `--platform linux/amd64` flag to your `docker run` commands.
Expand Down Expand Up @@ -190,14 +198,57 @@ docker run -d \
- Docker 20.10+ or compatible runtime
- All other system requirements same as binary installation

## External Miner Setup

For high-performance mining, you can offload the QPoW mining process to a separate service, freeing up node resources.

### Prerequisites

1. **Build Node:**
```bash
# From workspace root
cargo build --release -p quantus-node
```

2. **Get External Miner:**
```bash
git clone https://github.com/Quantus-Network/quantus-miner
cd quantus-miner
cargo build --release
```

### Setup with Wormhole Addresses

1. **Generate Your Wormhole Address**:
```bash
./quantus-node key quantus --scheme wormhole
```
Save the `inner_hash` value.

2. **Start External Miner** (in separate terminal):
```bash
RUST_LOG=info ./target/release/quantus-miner
```
*(Default: `http://127.0.0.1:9833`)*

3. **Start Node with External Miner** (in another terminal):
```bash
# Replace <YOUR_PREIMAGE> with the inner_hash from step 1
RUST_LOG=info,sc_consensus_pow=debug ./target/release/quantus-node \
--validator \
--chain dirac \
--external-miner-url http://127.0.0.1:9833 \
--rewards-preimage <YOUR_PREIMAGE>
```

## Configuration Options

### Node Parameters

| Parameter | Description | Default |
|-----------|-------------|---------|
| `--node-key-file` | Path to P2P identity file | Required |
| `--rewards-address` | Path to rewards address file | Required |
| `--rewards-preimage` | Wormhole preimage (inner_hash from key generation) | Required |
| `--chain` | Chain specification | `dirac` |
| `--port` | P2P networking port | `30333` |
| `--prometheus-port` | Metrics endpoint port | `9616` |
Expand Down Expand Up @@ -234,14 +285,18 @@ curl -H "Content-Type: application/json" \

### Check Mining Rewards

**View Balance**
**View Balance at Your Wormhole Address**
```bash
# Replace YOUR_ADDRESS with your rewards address
# Replace YOUR_WORMHOLE_ADDRESS with your wormhole address from key generation
curl -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"faucet_getAccountInfo","params":["YOUR_ADDRESS"]}' \
-d '{"jsonrpc":"2.0","id":1,"method":"faucet_getAccountInfo","params":["YOUR_WORMHOLE_ADDRESS"]}' \
http://localhost:9944
```

**Find Your Wormhole Address**
- From key generation: Use the `Address` field from `./quantus-node key quantus --scheme wormhole`
- From node logs: Check startup logs for "Mining rewards will be sent to wormhole address"

## Testnet Information

- **Chain**: Dirac Testnet
Expand All @@ -268,9 +323,14 @@ quantus-node purge-chain --chain dirac

**Mining Not Working**
1. Check that `--validator` flag is present
2. Verify rewards address file exists and contains valid address
2. Verify your preimage from `inner_hash` field in key generation
3. Ensure node is synchronized (check logs for "Imported #XXXX")

**Wormhole Address Issues**
1. **Can't find rewards**: Check the `Address` field from your key generation
2. **Invalid preimage**: Use the exact `inner_hash` value from key generation
3. **Wrong address**: Rewards go to the wormhole address, not the preimage

**Connection Issues**
1. Check firewall settings (allow port 30333)
2. Verify internet connection
Expand Down Expand Up @@ -302,9 +362,11 @@ curl -H "Content-Type: application/json" \

## Mining Economics

### Rewards Structure
### Wormhole Address Rewards System

- **Block Rewards**: Earned by successfully mining blocks
- **Automatic Wormhole Addresses**: All mining rewards go to your wormhole address
- **Privacy by Design**: Your reward address is derived from your preimage
- **Block Rewards**: Earned by successfully mining blocks
- **Transaction Fees**: Collected from transactions in mined blocks
- **Network Incentives**: Additional rewards for network participation

Expand All @@ -320,9 +382,9 @@ Mining performance depends on:

### Key Management

- **Backup Your Keys**: Store copies of your node identity and rewards keys safely
- **Secure Storage**: Keep private keys in encrypted storage
- **Regular Rotation**: Consider rotating keys periodically for enhanced security
- **Backup Your Keys**: Securely store your wormhole key pair from key generation
- **Backup Node Keys**: Store copies of your node identity keys safely
- **Secure Storage**: Keep preimages and private keys in encrypted storage

### Node Security

Expand All @@ -341,8 +403,8 @@ This is testnet software for testing purposes only:
## Next Steps

1. **Join the Community**: Connect with other miners and developers
2. **Monitor Performance**: Track your mining efficiency and rewards
3. **Experiment**: Try different configurations and optimizations
2. **Monitor Performance**: Track your mining efficiency and rewards at your wormhole address
3. **Experiment**: Try different configurations and optimizations
4. **Contribute**: Help improve the network by reporting issues and feedback

Happy mining! 🚀
Expand Down
50 changes: 2 additions & 48 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,17 +57,9 @@ bip39 wordlist.

Seed must be a 64-character hex string

---

### Rewards address
## Mining

By providing the optional `--rewards-address` parameter, the node will start sending mining and transaction rewards
after each block confirmation by the runtime.
If this address is not specified, rewards will not be minted.

```shell
./quantus-node --chain local --validator --rewards-address <NODE_OPERATOR_ADDRESS>
```
For complete mining setup instructions, including wormhole address requirements and external miner configuration, see [MINING.md](MINING.md).

## Local dev run

Expand All @@ -81,44 +73,6 @@ If this address is not specified, rewards will not be minted.
./target/release/quantus-node --dev
```

## Run with External Miner

---

This node supports offloading the QPoW mining process to a separate service, freeing up node resources.

Any service that adheres to the API spec below can be used as miner by the node. We provide a sample implementation in
the 'miner' crate.

API classes are defined in the 'resonance-miner-api' crate.

**API Spec:
** [openapi.yaml](https://gitlab.com/resonance-network/backbone/-/blob/b37c4fcdb749ddddc747915b79149e29f537e92f/external-miner/api/openapi.yaml)

1. **Build Node & Miner:**
```bash
# From workspace root
cargo build --release -p quantus-node
```

2. **Run External Miner:** (In a separate terminal)
```bash
git clone https://github.com/Quantus-Network/quantus-miner
cd quantus-miner
cargo build --release
RUST_LOG=info ./target/release/quantus-miner
```
*(Listens on `http://127.0.0.1:9833` by default)*

3. **Run Node:** (In another terminal)
```bash
# From workspace root (replace <YOUR_REWARDS_ADDRESS>)
RUST_LOG=info,sc_consensus_pow=debug ./target/release/quantus-node \
--dev \
--external-miner-url http://127.0.0.1:9833 \
--rewards-address <YOUR_REWARDS_ADDRESS>
```

## Multinode local run

---
Expand Down
7 changes: 4 additions & 3 deletions client/cli/src/commands/generate_node_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
use crate::{build_network_key_dir_or_default, Error, NODE_KEY_DILITHIUM_FILE};
use clap::{Args, Parser};
use libp2p_identity::PublicKey;
use qp_rusty_crystals_dilithium::ml_dsa_87::Keypair;
use qp_rusty_crystals_dilithium::{ml_dsa_87::Keypair, SensitiveBytes32};
use sc_service::BasePath;
use sp_core::blake2_256;
use std::{
Expand Down Expand Up @@ -116,8 +116,9 @@ fn generate_key(
default_base_path: bool,
executable_name: Option<&String>,
) -> Result<(), Error> {
let hashed_timestamp = hash_current_time_to_hex();
let keypair = Keypair::generate(&hashed_timestamp);
let mut hashed_timestamp = hash_current_time_to_hex();
let entropy = SensitiveBytes32::from(&mut hashed_timestamp);
let keypair = Keypair::generate(entropy);

let file_data = if bin {
keypair.to_bytes().to_vec()
Expand Down
Loading
Loading