Skip to content

Commit e59b28e

Browse files
committed
Add missing activation code generation endpoint
- Add /api/v1/generate-activation-code endpoint for quantum-secure code generation - Implement verify_burn_transaction_exists() for Solana/QNet validation - Implement generate_quantum_activation_code() with deterministic entropy - Support both Phase 1 (1DEV burn) and Phase 2 (QNC Pool 3) validation - Prevent duplicate codes through blockchain registry integration - Ensure quantum-secure cryptographic binding to wallet addresses - Format: QNET-XXXX-XXXX-XXXX (17 chars) with node type prefix - Production-ready compilation verified
1 parent 37a4928 commit e59b28e

10 files changed

Lines changed: 927 additions & 39 deletions

File tree

‎README.md‎

Lines changed: 49 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,18 @@ git pull origin testnet
188188
docker build -f development/qnet-integration/Dockerfile.production -t qnet-production .
189189

190190
# Run interactive production node (ONLY activation method)
191-
docker run -it --name qnet-node --restart=always \
191+
# For TESTNET:
192+
docker run -it --name qnet-testnet-node --restart=always \
193+
-e QNET_NETWORK=testnet \
192194
-p 9876:9876 -p 9877:9877 -p 8001:8001 \
193-
-v $(pwd)/node_data:/app/node_data \
195+
-v $(pwd)/testnet_node_data:/app/node_data \
196+
qnet-production
197+
198+
# For MAINNET:
199+
docker run -it --name qnet-mainnet-node --restart=always \
200+
-e QNET_NETWORK=mainnet \
201+
-p 9876:9876 -p 9877:9877 -p 8001:8001 \
202+
-v $(pwd)/mainnet_node_data:/app/node_data \
194203
qnet-production
195204
```
196205

@@ -630,37 +639,65 @@ docker logs qnet-node | grep "\[DEBUG\]\|\[INFO\]\|\[WARN\]\|\[ERROR\]"
630639
For genesis bootstrap nodes (production network initialization):
631640

632641
```bash
642+
# TESTNET Genesis Nodes:
633643
# Genesis Node #001 (NorthAmerica)
634-
docker run -d --name qnet-node --restart=always \
644+
docker run -d --name qnet-testnet-genesis-001 --restart=always \
645+
-e QNET_NETWORK=testnet \
635646
-e QNET_PRODUCTION=1 \
636647
-e QNET_BOOTSTRAP_ID=001 \
637648
-p 9876:9876 -p 9877:9877 -p 8001:8001 \
638-
-v $(pwd)/node_data:/app/data \
649+
-v $(pwd)/testnet_genesis_001:/app/data \
639650
qnet-production
640651

641652
# Genesis Node #002 (Europe)
642-
docker run -d --name qnet-node-002 --restart=always \
653+
docker run -d --name qnet-testnet-genesis-002 --restart=always \
654+
-e QNET_NETWORK=testnet \
643655
-e QNET_PRODUCTION=1 \
644656
-e QNET_BOOTSTRAP_ID=002 \
645657
-p 9878:9876 -p 9879:9877 -p 8002:8001 \
646-
-v $(pwd)/node_data_002:/app/data \
658+
-v $(pwd)/testnet_genesis_002:/app/data \
647659
qnet-production
648660

649-
# Genesis Node #003 (Asia)
650-
docker run -d --name qnet-node-003 --restart=always \
661+
# MAINNET Genesis Nodes:
662+
# Genesis Node #001 (NorthAmerica)
663+
docker run -d --name qnet-mainnet-genesis-001 --restart=always \
664+
-e QNET_NETWORK=mainnet \
651665
-e QNET_PRODUCTION=1 \
652-
-e QNET_BOOTSTRAP_ID=003 \
653-
-p 9880:9876 -p 9881:9877 -p 8003:8001 \
654-
-v $(pwd)/node_data_003:/app/data \
666+
-e QNET_BOOTSTRAP_ID=001 \
667+
-p 9876:9876 -p 9877:9877 -p 8001:8001 \
668+
-v $(pwd)/mainnet_genesis_001:/app/data \
655669
qnet-production
656670
```
657671

658672
**Genesis Node Requirements:**
659673
- Set `QNET_BOOTSTRAP_ID` to 001-005 for genesis nodes
660674
- Use different ports for multiple nodes on same server
661-
- Create separate data directories for each node
675+
- Create separate data directories for each node
662676
- Ensure proper file permissions: `chmod 777 node_data_XXX/`
663677

678+
### Quick Testnet Launch (5 Genesis Nodes)
679+
680+
For rapid testnet deployment with coordinated genesis nodes:
681+
682+
```bash
683+
# Launch complete testnet (5 genesis nodes + bridge)
684+
docker-compose -f docker-compose.testnet.yml up -d
685+
686+
# Monitor testnet startup
687+
docker-compose -f docker-compose.testnet.yml logs -f
688+
689+
# Stop testnet
690+
docker-compose -f docker-compose.testnet.yml down
691+
```
692+
693+
**Testnet Endpoints:**
694+
- Genesis Node 1: http://localhost:8001
695+
- Genesis Node 2: http://localhost:8002
696+
- Genesis Node 3: http://localhost:8003
697+
- Genesis Node 4: http://localhost:8004
698+
- Genesis Node 5: http://localhost:8005
699+
- Bridge Server: http://localhost:8080
700+
664701
### Backup & Recovery
665702

666703
```bash

‎applications/qnet-mobile/src/services/BridgeService.js‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ class BridgeServiceClass {
1515
local: 'http://localhost:8080' // For development
1616
};
1717

18-
this.currentEndpoint = this.bridgeEndpoints.testnet;
18+
// Auto-detect network from environment
19+
const networkEnv = process.env.QNET_NETWORK || 'testnet';
20+
this.currentEndpoint = this.bridgeEndpoints[networkEnv] || this.bridgeEndpoints.testnet;
1921
this.isConnected = false;
2022
this.authToken = null;
2123

‎applications/qnet-mobile/src/services/NetworkService.js‎

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,27 @@ class NetworkServiceClass {
5454

5555
async getSolanaEndpoint() {
5656
const saved = await AsyncStorage.getItem('solanaEndpoint');
57-
return saved || this.endpoints.solana.devnet; // Default to devnet for testing
57+
if (saved) return saved;
58+
59+
// Auto-detect network from environment
60+
const networkEnv = process.env.QNET_NETWORK || 'testnet';
61+
return networkEnv === 'mainnet'
62+
? this.endpoints.solana.mainnet
63+
: this.endpoints.solana.devnet; // Default to devnet for testnet
5864
}
5965

6066
async initializeQNetConnection() {
6167
try {
6268
const qnetEndpoint = await AsyncStorage.getItem('qnetEndpoint');
63-
const endpoint = qnetEndpoint || this.endpoints.qnet.testnet;
69+
if (qnetEndpoint) {
70+
var endpoint = qnetEndpoint;
71+
} else {
72+
// Auto-detect network from environment
73+
const networkEnv = process.env.QNET_NETWORK || 'testnet';
74+
var endpoint = networkEnv === 'mainnet'
75+
? this.endpoints.qnet.mainnet
76+
: this.endpoints.qnet.testnet;
77+
}
6478

6579
// Initialize QNet connection (placeholder - will be replaced with actual QNet client)
6680
this.qnetConnection = {
@@ -274,7 +288,11 @@ class NetworkServiceClass {
274288
async getQNetData(eonAddress) {
275289
try {
276290
// Real QNet API calls using the actual network
277-
const apiUrl = process.env.REACT_NATIVE_QNET_API_URL || 'https://api.qnet.io';
291+
const networkEnv = process.env.QNET_NETWORK || 'testnet';
292+
const defaultApiUrl = networkEnv === 'mainnet'
293+
? this.endpoints.qnet.mainnet
294+
: this.endpoints.qnet.testnet;
295+
const apiUrl = process.env.REACT_NATIVE_QNET_API_URL || defaultApiUrl;
278296

279297
// Get QNC balance from QNet blockchain
280298
const balanceResponse = await fetch(`${apiUrl}/v1/balances/${eonAddress}`, {

‎deployment/production-bridge/bridge-server.py‎

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -530,8 +530,15 @@ async def get_1dev_burn_contract_info():
530530
async def verify_user_1dev_burn(wallet_address: str, burn_amount: int) -> dict:
531531
"""PRODUCTION: Verify user actually burned 1DEV tokens on Solana blockchain"""
532532

533-
solana_rpc_url = "https://api.devnet.solana.com" # Use devnet for our 1DEV token
534-
onedev_mint = "62PPztDN8t6dAeh3FvxXfhkDJirpHZjGvCYdHM54FHHJ" # Real 1DEV token mint
533+
# PRODUCTION: Network-aware configuration
534+
network_env = os.environ.get('QNET_NETWORK', 'testnet').lower()
535+
536+
if network_env == 'mainnet':
537+
solana_rpc_url = "https://api.mainnet-beta.solana.com"
538+
onedev_mint = "MAINNET_1DEV_MINT_TBD" # Will be set when mainnet launches
539+
else:
540+
solana_rpc_url = "https://api.devnet.solana.com" # Testnet uses devnet
541+
onedev_mint = "62PPztDN8t6dAeh3FvxXfhkDJirpHZjGvCYdHM54FHHJ" # Real testnet token
535542
burn_address = "1nc1nerator11111111111111111111111111111111" # Official Solana incinerator
536543

537544
try:
@@ -759,7 +766,9 @@ async def query_blockchain_for_existing_activation(wallet_address: str, phase: i
759766
async def verify_solana_wallet_exists(wallet_address: str) -> bool:
760767
"""Verify wallet address exists on Solana network"""
761768

762-
solana_rpc_url = "https://api.devnet.solana.com"
769+
# PRODUCTION: Network-aware Solana RPC
770+
network_env = os.environ.get('QNET_NETWORK', 'testnet').lower()
771+
solana_rpc_url = "https://api.mainnet-beta.solana.com" if network_env == 'mainnet' else "https://api.devnet.solana.com"
763772

764773
try:
765774
async with httpx.AsyncClient() as client:

‎development/qnet-integration/Cargo.toml‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ serde = { version = "1.0.195", features = ["derive"] }
2828
serde_json = "1.0.111"
2929
bincode = "1.3.3"
3030

31+
# Configuration already included above
32+
3133
# Cryptography - modern production versions with edition constraints
3234
blake3 = "1.5.0"
3335
ed25519-dalek = { version = "2.0.0", features = ["std"] }

‎development/qnet-integration/src/bin/qnet-node.rs‎

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -681,16 +681,25 @@ async fn detect_current_phase() -> (u8, PricingInfo) {
681681
println!(" Error: {}", e);
682682
println!(" Trying backup RPC nodes...");
683683

684-
// Try backup devnet RPC nodes
685-
let backup_rpcs = vec![
686-
"https://api.devnet.solana.com",
687-
"https://devnet.helius-rpc.com",
688-
"https://solana-devnet.g.alchemy.com/v2/demo",
689-
];
684+
// Try backup RPC nodes (network-aware)
685+
let network_config = qnet_integration::network_config::get_network_config();
686+
let backup_rpcs = if network_config.is_testnet() {
687+
vec![
688+
"https://api.devnet.solana.com",
689+
"https://devnet.helius-rpc.com",
690+
"https://solana-devnet.g.alchemy.com/v2/demo",
691+
]
692+
} else {
693+
vec![
694+
"https://api.mainnet-beta.solana.com",
695+
"https://solana-mainnet.g.alchemy.com/v2/demo",
696+
"https://mainnet.helius-rpc.com",
697+
]
698+
};
690699

691700
for rpc_url in backup_rpcs {
692701
println!("🔄 Trying backup RPC: {}", rpc_url);
693-
match get_real_token_supply(rpc_url, "62PPztDN8t6dAeh3FvxXfhkDJirpHZjGvCYdHM54FHHJ").await {
702+
match get_real_token_supply(rpc_url, &network_config.solana.onedev_mint).await {
694703
Ok(supply_data) => {
695704
println!("✅ Data retrieved from backup RPC!");
696705

@@ -774,9 +783,10 @@ struct RealNodeCounts {
774783

775784
// Fetch real data from Solana contract
776785
async fn fetch_burn_tracker_data() -> Result<BurnTrackerData, String> {
777-
// Testnet Solana RPC configuration (devnet)
786+
// Network-aware Solana RPC configuration
787+
let network_config = qnet_integration::network_config::get_network_config();
778788
let rpc_url = std::env::var("SOLANA_RPC_URL").unwrap_or_else(|_| {
779-
"https://api.devnet.solana.com".to_string()
789+
network_config.solana.rpc_url.clone()
780790
});
781791

782792
let program_id = std::env::var("BURN_TRACKER_PROGRAM_ID").unwrap_or_else(|_| {
@@ -854,8 +864,9 @@ async fn get_real_token_supply(rpc_url: &str, token_mint: &str) -> Result<TokenS
854864
token_mint
855865
);
856866

867+
let network_config = qnet_integration::network_config::get_network_config();
857868
match tokio::process::Command::new("curl")
858-
.args(&["-s", "-X", "POST", "https://api.devnet.solana.com"])
869+
.args(&["-s", "-X", "POST", &network_config.solana.rpc_url])
859870
.args(&["-H", "Content-Type: application/json"])
860871
.args(&["-d", &payload])
861872
.output()
@@ -2096,6 +2107,16 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
20962107
return Err("No activation code provided".into());
20972108
}
20982109

2110+
// PRODUCTION: Load network configuration based on QNET_NETWORK env
2111+
let network_config = qnet_integration::network_config::get_network_config();
2112+
println!("🌐 Network: {}", network_config.network_name());
2113+
println!(" Environment: {:?}", network_config.environment);
2114+
println!(" Chain ID: {}", network_config.chain_id);
2115+
println!(" QNet RPC: {}", network_config.endpoints.qnet_rpc);
2116+
println!(" Bridge API: {}", network_config.endpoints.bridge_api);
2117+
println!(" Solana RPC: {}", network_config.solana.rpc_url);
2118+
println!(" 1DEV Token: {}", network_config.solana.onedev_mint);
2119+
20992120
// PRODUCTION: Full activation code validation in main for security
21002121
let (current_phase, pricing_info) = detect_current_phase().await;
21012122

@@ -2816,8 +2837,9 @@ async fn verify_1dev_burn(node_type: &NodeType) -> Result<(), String> {
28162837
async fn verify_solana_burn_transaction(wallet_address: &str, required_amount: f64) -> Result<bool, String> {
28172838
println!("📡 Querying Solana devnet for burn transaction...");
28182839

2819-
// PRODUCTION: Use devnet RPC for our 1DEV token
2820-
let solana_rpc = "https://api.devnet.solana.com";
2840+
// PRODUCTION: Use network-aware RPC configuration
2841+
let network_config = qnet_integration::network_config::get_network_config();
2842+
let solana_rpc = &network_config.solana.rpc_url;
28212843

28222844
// Build RPC request to check burn transactions
28232845
let request_body = serde_json::json!({
@@ -2874,10 +2896,11 @@ async fn verify_solana_burn_transaction(wallet_address: &str, required_amount: f
28742896
async fn verify_solana_burn_for_activation(wallet_address: &str, expected_tx_hash: &str, required_amount: u64) -> Result<bool, String> {
28752897
println!("📡 PRODUCTION: Verifying 1DEV burn on Solana for node activation...");
28762898

2877-
// PRODUCTION: Use devnet RPC for our 1DEV token
2878-
let solana_rpc = "https://api.devnet.solana.com";
2879-
let onedev_mint = "62PPztDN8t6dAeh3FvxXfhkDJirpHZjGvCYdHM54FHHJ"; // Real 1DEV token mint
2880-
let burn_address = "1nc1nerator11111111111111111111111111111111"; // Official Solana incinerator
2899+
// PRODUCTION: Use network-aware RPC configuration
2900+
let network_config = qnet_integration::network_config::get_network_config();
2901+
let solana_rpc = &network_config.solana.rpc_url;
2902+
let onedev_mint = &network_config.solana.onedev_mint;
2903+
let burn_address = &network_config.solana.burn_address;
28812904

28822905
// Convert to 6 decimals for comparison
28832906
let required_amount_decimals = required_amount * 1_000_000;
@@ -2994,7 +3017,8 @@ async fn verify_solana_burn_for_activation(wallet_address: &str, expected_tx_has
29943017

29953018
async fn is_burn_transaction(signature: &str) -> Result<bool, String> {
29963019
// Query transaction details to check if it's a burn to 1DEV burn address
2997-
let solana_rpc = "https://api.devnet.solana.com";
3020+
let network_config = qnet_integration::network_config::get_network_config();
3021+
let solana_rpc = &network_config.solana.rpc_url;
29983022

29993023
let request_body = serde_json::json!({
30003024
"jsonrpc": "2.0",
@@ -3039,7 +3063,8 @@ async fn is_burn_transaction(signature: &str) -> Result<bool, String> {
30393063

30403064
async fn get_burned_amount(signature: &str) -> Result<f64, String> {
30413065
// Parse burn amount from transaction
3042-
let solana_rpc = "https://api.devnet.solana.com";
3066+
let network_config = qnet_integration::network_config::get_network_config();
3067+
let solana_rpc = &network_config.solana.rpc_url;
30433068

30443069
let request_body = serde_json::json!({
30453070
"jsonrpc": "2.0",

‎development/qnet-integration/src/lib.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub mod genesis;
1717
pub mod blockchain;
1818
pub mod activation_validation;
1919
pub mod quantum_crypto;
20+
pub mod network_config;
2021

2122
use std::sync::Arc;
2223
use tokio::sync::RwLock;

0 commit comments

Comments
 (0)