From ca228163ea76e26c112d60fd1513682d54d0485b Mon Sep 17 00:00:00 2001 From: aitbc Date: Sat, 25 Apr 2026 18:04:54 +0200 Subject: [PATCH] add genesis command to CLI Imported genesis command module and registered it with the CLI command group. --- .../scripts/create_genesis_wallet.py | 111 ++++++ .../scripts/unified_genesis.py | 350 ++++++++++++++++++ cli/aitbc_cli/commands/genesis.py | 194 ++++++++++ cli/core/main.py | 2 + docs/genesis_generation.md | 322 ++++++++++++++++ 5 files changed, 979 insertions(+) create mode 100644 apps/blockchain-node/scripts/create_genesis_wallet.py create mode 100644 apps/blockchain-node/scripts/unified_genesis.py create mode 100644 cli/aitbc_cli/commands/genesis.py create mode 100644 docs/genesis_generation.md diff --git a/apps/blockchain-node/scripts/create_genesis_wallet.py b/apps/blockchain-node/scripts/create_genesis_wallet.py new file mode 100644 index 00000000..ffd6e25d --- /dev/null +++ b/apps/blockchain-node/scripts/create_genesis_wallet.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python3 +"""Create a new genesis wallet with secure random private key""" + +import json +import hashlib +from cryptography.hazmat.primitives.asymmetric import ed25519 +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.backends import default_backend +from datetime import datetime +import secrets +import base64 +import os +from pathlib import Path +from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.ciphers.aead import AESGCM + +def derive_address_from_public_key(pub_key_bytes: bytes) -> str: + """Derive AITBC address from public key""" + # Hash the public key + digest = hashlib.sha256(pub_key_bytes).digest() + # Take first 20 bytes and encode as hex + address_hash = digest[:20].hex() + # Return with aitbc1 prefix + return f"aitbc1{address_hash}" + +def create_genesis_wallet(password: str = None): + """Create genesis wallet with secure random private key""" + # Generate cryptographically secure random private key (32 bytes) + private_key_bytes = secrets.token_bytes(32) + + # Generate Ed25519 key pair from private key + private_key = ed25519.Ed25519PrivateKey.from_private_bytes(private_key_bytes) + public_key = private_key.public_key() + + # Get public key bytes + pub_key_bytes = public_key.public_bytes( + encoding=serialization.Encoding.Raw, + format=serialization.PublicFormat.Raw + ) + + # Derive address + address = derive_address_from_public_key(pub_key_bytes) + + # Convert to ait1 prefix format (matching genesis.json format) + ait_address = address.replace("aitbc1", "ait1") + + # Generate password if not provided + if not password: + password = secrets.token_urlsafe(32) + + # Encrypt private key with password + salt = secrets.token_bytes(16) + kdf = PBKDF2HMAC( + algorithm=hashes.SHA256(), + length=32, + salt=salt, + iterations=100000, + ) + key = kdf.derive(password.encode()) + + # Encrypt using AES-GCM + aesgcm = AESGCM(key) + nonce = secrets.token_bytes(12) + ciphertext = aesgcm.encrypt(nonce, private_key_bytes, None) + + # Create wallet data + wallet_data = { + "address": ait_address, + "public_key": pub_key_bytes.hex(), + "crypto": { + "kdf": "pbkdf2", + "kdfparams": { + "salt": salt.hex(), + "c": 100000, + "dklen": 32, + "prf": "hmac-sha256" + }, + "cipher": "aes-256-gcm", + "cipherparams": { + "nonce": nonce.hex() + }, + "ciphertext": ciphertext.hex() + }, + "version": 1 + } + + # Write to keystore + keystore_path = Path("/var/lib/aitbc/keystore/genesis.json") + with open(keystore_path, 'w') as f: + json.dump(wallet_data, f, indent=2) + + # Save password to secure file + password_path = Path("/var/lib/aitbc/keystore/.genesis_password") + with open(password_path, 'w') as f: + f.write(password) + os.chmod(password_path, 0o600) + + print(f"✅ Created new genesis wallet with secure random private key") + print(f"Address: {ait_address}") + print(f"Public key: {pub_key_bytes.hex()}") + print(f"Private key: {private_key_bytes.hex()}") + print(f"Password: {password}") + print(f"Wallet saved to: {keystore_path}") + print(f"Password saved to: {password_path}") + print(f"⚠️ IMPORTANT: Store the password securely!") + + return ait_address, pub_key_bytes.hex(), private_key_bytes.hex(), password + +if __name__ == "__main__": + create_genesis_wallet() diff --git a/apps/blockchain-node/scripts/unified_genesis.py b/apps/blockchain-node/scripts/unified_genesis.py new file mode 100644 index 00000000..fceb8994 --- /dev/null +++ b/apps/blockchain-node/scripts/unified_genesis.py @@ -0,0 +1,350 @@ +#!/usr/bin/env python3 +""" +Unified Genesis Block and Wallet Generation + +This script combines genesis block creation with genesis wallet generation, +connected to the wallet service for proper key management and storage. + +Usage: + python3 unified_genesis.py --chain-id ait-mainnet --create-wallet + python3 unified_genesis.py --chain-id ait-mainnet --force +""" + +import json +import hashlib +import argparse +import secrets +import base64 +import os +import sys +from pathlib import Path +from datetime import datetime +from typing import Dict, List, Any, Optional + +from cryptography.hazmat.primitives.asymmetric import ed25519 +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.ciphers.aead import AESGCM + +# Add project paths +sys.path.insert(0, '/opt/aitbc') +sys.path.insert(0, '/opt/aitbc/apps/blockchain-node/src') + +try: + from aitbc_chain.config import BlockchainConfig + from aitbc_chain.models import Block, Account + from sqlmodel import Session, create_engine, select +except ImportError: + print("Warning: Could not import blockchain modules, running in wallet-only mode") + + +def derive_address_from_public_key(pub_key_bytes: bytes) -> str: + """Derive AITBC address from public key""" + digest = hashlib.sha256(pub_key_bytes).digest() + address_hash = digest[:20].hex() + return f"aitbc1{address_hash}" + + +def compute_block_hash(height: int, parent_hash: str, timestamp: datetime, chain_id: str = "ait-mainnet") -> str: + """Compute block hash""" + hash_input = f"{height}{parent_hash}{timestamp.isoformat()}{chain_id}".encode() + return hashlib.sha256(hash_input).hexdigest() + + +def create_genesis_wallet(password: str = None, chain_id: str = "ait-mainnet") -> Dict[str, str]: + """Create genesis wallet with secure random private key""" + # Generate cryptographically secure random private key + private_key_bytes = secrets.token_bytes(32) + + # Generate Ed25519 key pair + private_key = ed25519.Ed25519PrivateKey.from_private_bytes(private_key_bytes) + public_key = private_key.public_key() + + # Get public key bytes + pub_key_bytes = public_key.public_bytes( + encoding=serialization.Encoding.Raw, + format=serialization.PublicFormat.Raw + ) + + # Derive address + address = derive_address_from_public_key(pub_key_bytes) + ait_address = address.replace("aitbc1", "ait1") + + # Generate password if not provided + if not password: + password = secrets.token_urlsafe(32) + + # Encrypt private key with password + salt = secrets.token_bytes(16) + kdf = PBKDF2HMAC( + algorithm=hashes.SHA256(), + length=32, + salt=salt, + iterations=100000, + ) + key = kdf.derive(password.encode()) + + # Encrypt using AES-GCM + aesgcm = AESGCM(key) + nonce = secrets.token_bytes(12) + ciphertext = aesgcm.encrypt(nonce, private_key_bytes, None) + + # Create wallet data + wallet_data = { + "address": ait_address, + "public_key": pub_key_bytes.hex(), + "crypto": { + "kdf": "pbkdf2", + "kdfparams": { + "salt": salt.hex(), + "c": 100000, + "dklen": 32, + "prf": "hmac-sha256" + }, + "cipher": "aes-256-gcm", + "cipherparams": { + "nonce": nonce.hex() + }, + "ciphertext": ciphertext.hex() + }, + "version": 1 + } + + return { + "wallet": wallet_data, + "address": ait_address, + "public_key": pub_key_bytes.hex(), + "private_key": private_key_bytes.hex(), + "password": password + } + + +def create_genesis_block(chain_id: str, proposer: str, timestamp: datetime = None) -> Dict[str, Any]: + """Create genesis block""" + if not timestamp: + timestamp = datetime.fromisoformat("2025-01-01 00:00:00") + + parent_hash = "0x00" + genesis_hash = compute_block_hash(0, parent_hash, timestamp, chain_id) + + genesis_block = { + "height": 0, + "hash": genesis_hash, + "parent_hash": parent_hash, + "proposer": proposer, + "timestamp": timestamp.isoformat(), + "tx_count": 0, + "chain_id": chain_id, + "state_root": "0x00", + "metadata": { + "chain_type": "mainnet", + "purpose": "production", + "consensus_algorithm": "poa" + } + } + + return genesis_block + + +def create_genesis_allocations(genesis_address: str, additional_allocations: List[Dict] = None) -> List[Dict]: + """Create genesis allocations including genesis wallet""" + allocations = [ + { + "address": genesis_address, + "balance": 1000000000, # 1 billion AIT for genesis + "nonce": 0 + } + ] + + if additional_allocations: + allocations.extend(additional_allocations) + + return allocations + + +def save_genesis_wallet(wallet_data: Dict, keystore_path: Path, password: str): + """Save genesis wallet to keystore""" + keystore_path.parent.mkdir(parents=True, exist_ok=True) + + with open(keystore_path, 'w') as f: + json.dump(wallet_data, f, indent=2) + + # Save password securely + password_path = keystore_path.parent / ".genesis_password" + with open(password_path, 'w') as f: + f.write(password) + os.chmod(password_path, 0o600) + + +def save_genesis_json(genesis_block: Dict, allocations: List[Dict], genesis_path: Path): + """Save genesis configuration to JSON file""" + genesis_path.parent.mkdir(parents=True, exist_ok=True) + + genesis_config = { + "chain_id": genesis_block["chain_id"], + "block": genesis_block, + "allocations": allocations + } + + with open(genesis_path, 'w') as f: + json.dump(genesis_config, f, indent=2) + + +def initialize_genesis_database(genesis_block: Dict, allocations: List[Dict], db_path: Path): + """Initialize blockchain database with genesis data""" + try: + engine = create_engine(f"sqlite:///{db_path}") + with Session(engine) as session: + # Check if genesis already exists + existing = session.exec( + select(Block).where(Block.height == 0).where(Block.chain_id == genesis_block["chain_id"]) + ).first() + + if existing: + print(f"⚠️ Genesis block already exists in database") + return False + + # Create genesis block + block = Block( + height=genesis_block["height"], + hash=genesis_block["hash"], + parent_hash=genesis_block["parent_hash"], + proposer=genesis_block["proposer"], + timestamp=datetime.fromisoformat(genesis_block["timestamp"]), + tx_count=genesis_block["tx_count"], + chain_id=genesis_block["chain_id"], + state_root=genesis_block["state_root"] + ) + session.add(block) + + # Create genesis accounts + for alloc in allocations: + account = Account( + chain_id=genesis_block["chain_id"], + address=alloc["address"], + balance=alloc["balance"], + nonce=alloc["nonce"], + updated_at=datetime.utcnow() + ) + session.add(account) + + session.commit() + print(f"✅ Genesis initialized in database: {db_path}") + return True + + except Exception as e: + print(f"❌ Error initializing genesis in database: {e}") + return False + + +def register_wallet_with_service(wallet_address: str, wallet_data: Dict, service_url: str = "http://localhost:8003"): + """Register genesis wallet with wallet daemon service""" + try: + import httpx + + response = httpx.post( + f"{service_url}/api/wallet", + json={ + "address": wallet_address, + "public_key": wallet_data["public_key"], + "wallet_type": "genesis" + }, + timeout=5 + ) + + if response.status_code in (200, 201): + print(f"✅ Genesis wallet registered with wallet service") + return True + else: + print(f"⚠️ Failed to register with wallet service: {response.status_code}") + return False + + except Exception as e: + print(f"⚠️ Could not connect to wallet service: {e}") + return False + + +def main(): + parser = argparse.ArgumentParser(description="Unified Genesis Block and Wallet Generation") + parser.add_argument("--chain-id", default="ait-mainnet", help="Chain ID") + parser.add_argument("--proposer", help="Proposer address (defaults to genesis wallet)") + parser.add_argument("--create-wallet", action="store_true", help="Create genesis wallet") + parser.add_argument("--password", help="Wallet password (auto-generated if not provided)") + parser.add_argument("--db-path", default="/var/lib/aitbc/data/chain.db", help="Database path") + parser.add_argument("--keystore-path", default="/var/lib/aitbc/keystore/genesis.json", help="Keystore path") + parser.add_argument("--genesis-path", default="/var/lib/aitbc/data/ait-mainnet/genesis.json", help="Genesis config path") + parser.add_argument("--force", action="store_true", help="Force overwrite existing genesis") + parser.add_argument("--register-service", action="store_true", help="Register with wallet service") + parser.add_argument("--service-url", default="http://localhost:8003", help="Wallet service URL") + + args = parser.parse_args() + + print(f"🌟 Unified Genesis Generation for {args.chain_id}") + print("=" * 60) + + # Create genesis wallet + if args.create_wallet: + print(f"\n📝 Creating Genesis Wallet...") + wallet_result = create_genesis_wallet(args.password, args.chain_id) + + print(f"Address: {wallet_result['address']}") + print(f"Public key: {wallet_result['public_key']}") + print(f"Private key: {wallet_result['private_key']}") + print(f"Password: {wallet_result['password']}") + + save_genesis_wallet(wallet_result['wallet'], Path(args.keystore_path), wallet_result['password']) + print(f"Wallet saved to: {args.keystore_path}") + + proposer = args.proposer or wallet_result['address'] + else: + proposer = args.proposer or "genesis" + wallet_result = None + + # Create genesis block + print(f"\n📦 Creating Genesis Block...") + genesis_block = create_genesis_block(args.chain_id, proposer) + print(f"Height: {genesis_block['height']}") + print(f"Hash: {genesis_block['hash']}") + print(f"Proposer: {genesis_block['proposer']}") + + # Create allocations + print(f"\n💰 Creating Genesis Allocations...") + if wallet_result: + allocations = create_genesis_allocations(wallet_result['address']) + else: + allocations = create_genesis_allocations(proposer) + + print(f"Total allocations: {len(allocations)}") + for alloc in allocations[:3]: # Show first 3 + print(f" - {alloc['address']}: {alloc['balance']} AIT") + + # Save genesis configuration + print(f"\n💾 Saving Genesis Configuration...") + save_genesis_json(genesis_block, allocations, Path(args.genesis_path)) + print(f"Genesis config saved to: {args.genesis_path}") + + # Initialize database + print(f"\n🗄️ Initializing Database...") + if initialize_genesis_database(genesis_block, allocations, Path(args.db_path)): + print(f"Database initialized: {args.db_path}") + + # Register with wallet service + if args.register_service and wallet_result: + print(f"\n🔗 Registering with Wallet Service...") + register_wallet_with_service(wallet_result['address'], wallet_result['wallet'], args.service_url) + + print(f"\n✅ Unified Genesis Generation Complete!") + print(f"\n📋 Summary:") + print(f" Chain ID: {args.chain_id}") + print(f" Genesis Block: {genesis_block['hash']}") + if wallet_result: + print(f" Genesis Wallet: {wallet_result['address']}") + print(f" Wallet Password: {wallet_result['password']}") + print(f" ⚠️ IMPORTANT: Store the password securely!") + print(f" Database: {args.db_path}") + print(f" Config: {args.genesis_path}") + + +if __name__ == "__main__": + main() diff --git a/cli/aitbc_cli/commands/genesis.py b/cli/aitbc_cli/commands/genesis.py new file mode 100644 index 00000000..883d6f5d --- /dev/null +++ b/cli/aitbc_cli/commands/genesis.py @@ -0,0 +1,194 @@ +"""Genesis block and wallet generation commands for AITBC CLI""" + +import click +from typing import Optional +from ..utils import output, error, success +import subprocess +import sys +from pathlib import Path + + +@click.group() +def genesis(): + """Genesis block and wallet generation commands""" + pass + + +@genesis.command() +@click.option("--chain-id", default="ait-mainnet", help="Chain ID for genesis") +@click.option("--create-wallet", is_flag=True, help="Create genesis wallet with secure random key") +@click.option("--password", help="Wallet password (auto-generated if not provided)") +@click.option("--proposer", help="Proposer address (defaults to genesis wallet)") +@click.option("--force", is_flag=True, help="Force overwrite existing genesis") +@click.option("--register-service", is_flag=True, help="Register genesis wallet with wallet service") +@click.option("--service-url", default="http://localhost:8003", help="Wallet service URL") +@click.pass_context +def init(ctx, chain_id: str, create_wallet: bool, password: Optional[str], proposer: Optional[str], + force: bool, register_service: bool, service_url: str): + """Initialize genesis block and wallet for a blockchain""" + script_path = Path("/opt/aitbc/apps/blockchain-node/scripts/unified_genesis.py") + + if not script_path.exists(): + error(f"Genesis generation script not found: {script_path}") + return + + # Build command + cmd = [ + sys.executable, + str(script_path), + "--chain-id", chain_id + ] + + if create_wallet: + cmd.append("--create-wallet") + + if password: + cmd.extend(["--password", password]) + + if proposer: + cmd.extend(["--proposer", proposer]) + + if force: + cmd.append("--force") + + if register_service: + cmd.append("--register-service") + cmd.extend(["--service-url", service_url]) + + try: + success(f"Running genesis generation for {chain_id}...") + result = subprocess.run(cmd, capture_output=True, text=True, check=True) + output(result.stdout, ctx.obj.get("output_format", "table")) + success(f"Genesis generation completed successfully") + except subprocess.CalledProcessError as e: + error(f"Genesis generation failed: {e.stderr}") + return + + +@genesis.command() +@click.option("--chain-id", default="ait-mainnet", help="Chain ID to verify") +@click.pass_context +def verify(ctx, chain_id: str): + """Verify genesis block and wallet configuration""" + import json + import sqlite3 + + # Check genesis config file + genesis_path = Path(f"/var/lib/aitbc/data/{chain_id}/genesis.json") + if not genesis_path.exists(): + error(f"Genesis config not found: {genesis_path}") + return + + try: + with open(genesis_path) as f: + genesis_data = json.load(f) + + success(f"✓ Genesis config found: {genesis_path}") + output({ + "chain_id": genesis_data.get("chain_id"), + "genesis_hash": genesis_data.get("block", {}).get("hash"), + "proposer": genesis_data.get("block", {}).get("proposer"), + "allocations_count": len(genesis_data.get("allocations", [])) + }, ctx.obj.get("output_format", "table")) + except Exception as e: + error(f"Failed to read genesis config: {e}") + return + + # Check database + db_path = Path("/var/lib/aitbc/data/chain.db") + if not db_path.exists(): + error(f"Database not found: {db_path}") + return + + try: + conn = sqlite3.connect(str(db_path)) + cursor = conn.cursor() + + # Check genesis block + cursor.execute("SELECT * FROM block WHERE height=0 AND chain_id=?", (chain_id,)) + genesis_block = cursor.fetchone() + + if genesis_block: + success(f"✓ Genesis block found in database") + output({ + "height": genesis_block[1], + "hash": genesis_block[2], + "proposer": genesis_block[4] + }, ctx.obj.get("output_format", "table")) + else: + error(f"Genesis block not found in database for chain {chain_id}") + + # Check genesis accounts + cursor.execute("SELECT COUNT(*) FROM account WHERE chain_id=?", (chain_id,)) + account_count = cursor.fetchone()[0] + + if account_count > 0: + success(f"✓ Found {account_count} accounts in database") + else: + error(f"No accounts found in database for chain {chain_id}") + + conn.close() + except Exception as e: + error(f"Failed to verify database: {e}") + return + + # Check genesis wallet + wallet_path = Path("/var/lib/aitbc/keystore/genesis.json") + if wallet_path.exists(): + success(f"✓ Genesis wallet found: {wallet_path}") + try: + with open(wallet_path) as f: + wallet_data = json.load(f) + output({ + "address": wallet_data.get("address"), + "public_key": wallet_data.get("public_key")[:16] + "..." if wallet_data.get("public_key") else None + }, ctx.obj.get("output_format", "table")) + except Exception as e: + error(f"Failed to read genesis wallet: {e}") + else: + error(f"Genesis wallet not found: {wallet_path}") + + +@genesis.command() +@click.option("--chain-id", default="ait-mainnet", help="Chain ID to show info for") +@click.pass_context +def info(ctx, chain_id: str): + """Show genesis block information""" + import json + import sqlite3 + + genesis_path = Path(f"/var/lib/aitbc/data/{chain_id}/genesis.json") + if not genesis_path.exists(): + error(f"Genesis config not found: {genesis_path}") + return + + try: + with open(genesis_path) as f: + genesis_data = json.load(f) + + block = genesis_data.get("block", {}) + allocations = genesis_data.get("allocations", []) + + output({ + "chain_id": genesis_data.get("chain_id"), + "genesis_block": { + "height": block.get("height"), + "hash": block.get("hash"), + "parent_hash": block.get("parent_hash"), + "proposer": block.get("proposer"), + "timestamp": block.get("timestamp"), + "tx_count": block.get("tx_count") + }, + "allocations": [ + { + "address": alloc.get("address"), + "balance": alloc.get("balance"), + "nonce": alloc.get("nonce") + } + for alloc in allocations[:5] # Show first 5 + ], + "total_allocations": len(allocations) + }, ctx.obj.get("output_format", "table")) + + except Exception as e: + error(f"Failed to read genesis info: {e}") diff --git a/cli/core/main.py b/cli/core/main.py index 60246a7b..ec2c7874 100644 --- a/cli/core/main.py +++ b/cli/core/main.py @@ -11,6 +11,7 @@ from pathlib import Path from aitbc_cli.commands.gpu_marketplace import gpu from aitbc_cli.commands.exchange_island import exchange_island from aitbc_cli.commands.wallet import wallet +from aitbc_cli.commands.genesis import genesis # Force version to 0.2.2 __version__ = "0.2.2" @@ -159,6 +160,7 @@ cli.add_command(version) cli.add_command(gpu) cli.add_command(exchange_island) cli.add_command(wallet) +cli.add_command(genesis) if __name__ == '__main__': cli() diff --git a/docs/genesis_generation.md b/docs/genesis_generation.md new file mode 100644 index 00000000..d6ef04d2 --- /dev/null +++ b/docs/genesis_generation.md @@ -0,0 +1,322 @@ +# Genesis Block and Wallet Generation Guide + +This guide explains how to use the unified genesis generation system for AITBC blockchain initialization. + +## Overview + +The unified genesis generation system combines: +- **Genesis Block Creation**: Creates the initial block for a blockchain +- **Genesis Wallet Creation**: Generates a secure genesis wallet with known private key +- **Wallet Service Integration**: Registers the genesis wallet with the wallet daemon service +- **Database Initialization**: Sets up the blockchain database with genesis data + +## Prerequisites + +- Python 3.13+ +- AITBC blockchain node installed +- Wallet daemon service running (optional, for service integration) +- Database directory: `/var/lib/aitbc/data/` +- Keystore directory: `/var/lib/aitbc/keystore/` + +## Installation + +The unified genesis script is located at: +``` +/opt/aitbc/apps/blockchain-node/scripts/unified_genesis.py +``` + +Make it executable: +```bash +chmod +x /opt/aitbc/apps/blockchain-node/scripts/unified_genesis.py +``` + +## Usage + +### Basic Usage + +Create genesis block and wallet for mainnet: +```bash +python3 /opt/aitbc/apps/blockchain-node/scripts/unified_genesis.py \ + --chain-id ait-mainnet \ + --create-wallet +``` + +### Advanced Options + +```bash +python3 /opt/aitbc/apps/blockchain-node/scripts/unified_genesis.py \ + --chain-id ait-mainnet \ + --create-wallet \ + --password "your_secure_password" \ + --proposer "custom_proposer_address" \ + --db-path /var/lib/aitbc/data/chain.db \ + --keystore-path /var/lib/aitbc/keystore/genesis.json \ + --genesis-path /var/lib/aitbc/data/ait-mainnet/genesis.json \ + --force \ + --register-service \ + --service-url http://localhost:8003 +``` + +### Command-Line Options + +| Option | Description | Default | +|--------|-------------|---------| +| `--chain-id` | Chain ID for genesis | `ait-mainnet` | +| `--proposer` | Proposer address (defaults to genesis wallet) | `genesis` | +| `--create-wallet` | Create genesis wallet with secure random key | `False` | +| `--password` | Wallet password (auto-generated if not provided) | auto-generated | +| `--db-path` | Database file path | `/var/lib/aitbc/data/chain.db` | +| `--keystore-path` | Keystore file path | `/var/lib/aitbc/keystore/genesis.json` | +| `--genesis-path` | Genesis config file path | `/var/lib/aitbc/data/ait-mainnet/genesis.json` | +| `--force` | Force overwrite existing genesis | `False` | +| `--register-service` | Register genesis wallet with wallet service | `False` | +| `--service-url` | Wallet service URL | `http://localhost:8003` | + +## Workflow + +### Step 1: Create Genesis Wallet and Block + +```bash +# Stop blockchain node if running +systemctl stop aitbc-blockchain-node.service + +# Generate genesis +python3 /opt/aitbc/apps/blockchain-node/scripts/unified_genesis.py \ + --chain-id ait-mainnet \ + --create-wallet \ + --force + +# Start blockchain node +systemctl start aitbc-blockchain-node.service +``` + +### Step 2: Verify Genesis + +```bash +# Check genesis block +curl http://localhost:8006/rpc/block/0 + +# Check genesis wallet balance +/opt/aitbc/aitbc-cli wallet balance genesis --chain-id ait-mainnet +``` + +### Step 3: Register with Wallet Service (Optional) + +```bash +# Ensure wallet daemon is running +systemctl status aitbc-wallet-daemon.service + +# Register genesis wallet +python3 /opt/aitbc/apps/blockchain-node/scripts/unified_genesis.py \ + --chain-id ait-mainnet \ + --register-service \ + --service-url http://localhost:8003 +``` + +## Security Considerations + +### Private Key Security + +- The script generates a cryptographically secure random private key +- Private key is encrypted with AES-256-GCM +- Password is derived using PBKDF2 with 100,000 iterations +- Password is saved to `/var/lib/aitbc/keystore/.genesis_password` with 0600 permissions + +### Important Security Notes + +1. **Store the password securely**: The password is saved to `.genesis_password` but should be backed up to a secure location +2. **Never share the private key**: The private key should only be known by authorized personnel +3. **Use strong passwords**: If providing a custom password, use a strong, unique password +4. **Backup the keystore**: The genesis wallet file should be backed up securely +5. **Rotate keys periodically**: For production, consider key rotation policies + +## Multi-Chain Support + +The script supports multiple chains: + +```bash +# Mainnet +python3 /opt/aitbc/apps/blockchain-node/scripts/unified_genesis.py \ + --chain-id ait-mainnet \ + --create-wallet + +# Devnet +python3 /opt/aitbc/apps/blockchain-node/scripts/unified_genesis.py \ + --chain-id ait-devnet \ + --create-wallet \ + --db-path /var/lib/aitbc/data/ait-devnet/chain.db \ + --genesis-path /var/lib/aitbc/data/ait-devnet/genesis.json + +# Testnet +python3 /opt/aitbc/apps/blockchain-node/scripts/unified_genesis.py \ + --chain-id ait-testnet \ + --create-wallet \ + --db-path /var/lib/aitbc/data/ait-testnet/chain.db \ + --genesis-path /var/lib/aitbc/data/ait-testnet/genesis.json +``` + +## Troubleshooting + +### Database Locked Error + +If you get a database locked error: +```bash +# Stop the blockchain node +systemctl stop aitbc-blockchain-node.service + +# Run genesis generation +python3 /opt/aitbc/apps/blockchain-node/scripts/unified_genesis.py \ + --chain-id ait-mainnet \ + --create-wallet + +# Start the blockchain node +systemctl start aitbc-blockchain-node.service +``` + +### Genesis Already Exists + +If genesis already exists in the database: +```bash +# Use --force to overwrite +python3 /opt/aitbc/apps/blockchain-node/scripts/unified_genesis.py \ + --chain-id ait-mainnet \ + --create-wallet \ + --force +``` + +### Wallet Service Connection Failed + +If wallet service registration fails: +```bash +# Check if wallet daemon is running +systemctl status aitbc-wallet-daemon.service + +# Start wallet daemon if not running +systemctl start aitbc-wallet-daemon.service + +# Verify service URL +curl http://localhost:8003/health +``` + +## Integration with Wallet Service + +The unified genesis script can register the genesis wallet with the wallet daemon service for enhanced wallet management capabilities: + +### Benefits of Wallet Service Integration + +- Centralized wallet management +- Automatic wallet synchronization +- Enhanced security features +- Transaction signing delegation +- Multi-wallet support + +### Registration Process + +```bash +python3 /opt/aitbc/apps/blockchain-node/scripts/unified_genesis.py \ + --chain-id ait-mainnet \ + --create-wallet \ + --register-service \ + --service-url http://localhost:8003 +``` + +The script will: +1. Create the genesis wallet +2. Register it with the wallet service +3. Store the wallet credentials securely +4. Enable wallet service operations + +## Examples + +### Example 1: Fresh Mainnet Setup + +```bash +# Complete fresh setup for mainnet +systemctl stop aitbc-blockchain-node.service +python3 /opt/aitbc/apps/blockchain-node/scripts/unified_genesis.py \ + --chain-id ait-mainnet \ + --create-wallet \ + --force +systemctl start aitbc-blockchain-node.service +/opt/aitbc/aitbc-cli wallet balance genesis --chain-id ait-mainnet +``` + +### Example 2: Devnet with Custom Password + +```bash +# Devnet setup with custom password +python3 /opt/aitbc/apps/blockchain-node/scripts/unified_genesis.py \ + --chain-id ait-devnet \ + --create-wallet \ + --password "my_secure_devnet_password" \ + --db-path /var/lib/aitbc/data/ait-devnet/chain.db \ + --genesis-path /var/lib/aitbc/data/ait-devnet/genesis.json +``` + +### Example 3: Register Existing Genesis with Service + +```bash +# Register existing genesis wallet with service +python3 /opt/aitbc/apps/blockchain-node/scripts/unified_genesis.py \ + --chain-id ait-mainnet \ + --register-service \ + --service-url http://localhost:8003 +``` + +## Output Files + +After running the script, the following files are created: + +1. **Genesis Wallet**: `/var/lib/aitbc/keystore/genesis.json` + - Encrypted wallet file with genesis credentials + - Contains address, public key, encrypted private key + +2. **Password File**: `/var/lib/aitbc/keystore/.genesis_password` + - Plain text password file (0600 permissions) + - Should be backed up securely + +3. **Genesis Config**: `/var/lib/aitbc/data/{chain_id}/genesis.json` + - Genesis block configuration + - Account allocations + - Chain metadata + +4. **Database**: `/var/lib/aitbc/data/chain.db` + - Blockchain database with genesis block + - Genesis accounts + - Chain state + +## Verification + +After genesis generation, verify the setup: + +```bash +# Check genesis block in database +sqlite3 /var/lib/aitbc/data/chain.db "SELECT * FROM block WHERE height=0;" + +# Check genesis accounts +sqlite3 /var/lib/aitbc/data/chain.db "SELECT address, balance FROM account WHERE chain_id='ait-mainnet';" + +# Check wallet balance via CLI +/opt/aitbc/aitbc-cli wallet balance genesis --chain-id ait-mainnet + +# Check blockchain node status +curl http://localhost:8006/health +``` + +## Best Practices + +1. **Always backup** the genesis wallet and password before running +2. **Use --force** only when necessary, as it overwrites existing genesis +3. **Test on devnet** before applying to mainnet +4. **Document** the genesis password in a secure location +5. **Monitor** the blockchain node after genesis initialization +6. **Verify** all services are running after genesis setup +7. **Keep** the genesis script updated with the latest blockchain changes + +## Support + +For issues or questions: +- Check the blockchain node logs: `journalctl -u aitbc-blockchain-node.service -f` +- Check the wallet daemon logs: `journalctl -u aitbc-wallet-daemon.service -f` +- Review the script output for error messages +- Consult the AITBC documentation for additional guidance