108 lines
3.5 KiB
Python
108 lines
3.5 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
"""
|
||
|
|
Generate IBFT 2.0 Genesis with Validator Addresses
|
||
|
|
This script extracts validator addresses from keys and creates proper genesis.json
|
||
|
|
"""
|
||
|
|
|
||
|
|
import json
|
||
|
|
import os
|
||
|
|
import subprocess
|
||
|
|
import sys
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
def extract_address_from_key(key_path):
|
||
|
|
"""Extract Ethereum address from private key using Besu or fallback method"""
|
||
|
|
if not os.path.exists(key_path):
|
||
|
|
return None
|
||
|
|
|
||
|
|
# Try Besu first
|
||
|
|
try:
|
||
|
|
result = subprocess.run(
|
||
|
|
['besu', 'public-key', 'export-address', '--node-private-key-file', key_path],
|
||
|
|
capture_output=True,
|
||
|
|
text=True,
|
||
|
|
timeout=10
|
||
|
|
)
|
||
|
|
if result.returncode == 0:
|
||
|
|
return result.stdout.strip()
|
||
|
|
except:
|
||
|
|
pass
|
||
|
|
|
||
|
|
# Fallback: Read private key and derive address (simplified)
|
||
|
|
# Note: This is a placeholder - proper address derivation requires secp256k1
|
||
|
|
try:
|
||
|
|
with open(key_path, 'r') as f:
|
||
|
|
priv_key = f.read().strip()
|
||
|
|
# For now, return None - requires proper crypto library
|
||
|
|
return None
|
||
|
|
except:
|
||
|
|
return None
|
||
|
|
|
||
|
|
def generate_extra_data(validator_addresses):
|
||
|
|
"""
|
||
|
|
Generate IBFT 2.0 extraData
|
||
|
|
Format: RLP([32 bytes Vanity, [][20 bytes]Validators, 65 bytes Signature])
|
||
|
|
This is a placeholder - proper encoding requires RLP library
|
||
|
|
"""
|
||
|
|
if not validator_addresses:
|
||
|
|
return "0x"
|
||
|
|
|
||
|
|
# This is a simplified placeholder
|
||
|
|
# Proper implementation requires:
|
||
|
|
# 1. RLP encoding library
|
||
|
|
# 2. Vanity bytes (32 bytes of zeros or custom data)
|
||
|
|
# 3. Validator addresses (20 bytes each)
|
||
|
|
# 4. Signature (65 bytes)
|
||
|
|
|
||
|
|
# For now, return placeholder that indicates validators exist
|
||
|
|
# Actual encoding must be done with Besu CLI
|
||
|
|
return "0x" + "00" * 32 + "".join([addr[2:] if addr.startswith("0x") else addr for addr in validator_addresses[:4]])[:80]
|
||
|
|
|
||
|
|
def main():
|
||
|
|
project_root = Path(__file__).parent.parent.parent
|
||
|
|
keys_dir = project_root / "keys" / "validators"
|
||
|
|
config_dir = project_root / "config"
|
||
|
|
|
||
|
|
# Find validator keys
|
||
|
|
validator_addresses = []
|
||
|
|
for i in range(1, 5):
|
||
|
|
key_path = keys_dir / f"validator-{i}" / "key.priv"
|
||
|
|
if key_path.exists():
|
||
|
|
addr = extract_address_from_key(str(key_path))
|
||
|
|
if addr:
|
||
|
|
validator_addresses.append(addr)
|
||
|
|
print(f"Found validator {i}: {addr}")
|
||
|
|
|
||
|
|
if not validator_addresses:
|
||
|
|
print("⚠️ No validator addresses extracted")
|
||
|
|
print("Note: Proper address extraction requires Besu CLI or secp256k1 library")
|
||
|
|
return 1
|
||
|
|
|
||
|
|
# Read existing genesis
|
||
|
|
genesis_path = config_dir / "genesis.json"
|
||
|
|
if not genesis_path.exists():
|
||
|
|
print(f"❌ Genesis file not found: {genesis_path}")
|
||
|
|
return 1
|
||
|
|
|
||
|
|
with open(genesis_path, 'r') as f:
|
||
|
|
genesis = json.load(f)
|
||
|
|
|
||
|
|
# Generate extraData (placeholder - requires proper RLP encoding)
|
||
|
|
extra_data = generate_extra_data(validator_addresses)
|
||
|
|
|
||
|
|
# Update genesis
|
||
|
|
genesis['extraData'] = extra_data
|
||
|
|
|
||
|
|
# Write updated genesis
|
||
|
|
with open(genesis_path, 'w') as f:
|
||
|
|
json.dump(genesis, f, indent=2)
|
||
|
|
|
||
|
|
print(f"✅ Updated genesis.json with {len(validator_addresses)} validators")
|
||
|
|
print(f"⚠️ Note: extraData is placeholder - use Besu CLI for proper encoding")
|
||
|
|
print(f" Run: besu operator generate-blockchain-config --config-file=config/genesis-template.json --to=keys/validators")
|
||
|
|
|
||
|
|
return 0
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
sys.exit(main())
|