mirror of
https://github.com/hanzoai/bootnode.git
synced 2026-09-30 20:46:32 +00:00
fix(nodes): correct luxd deploy to canonical Lux
- image luxfi/luxd:latest -> ghcr.io/luxfi/node:latest (the pullable one) - numeric network-id (localnet=1337/devnet=3/testnet=2/mainnet=1), drop Avalanche 'fuji' and 'subnet'/--track-subnets language - HTTP 9630 / staking 9631 (not 9650); --data-dir=/data - stage bundled VM plugins into --plugin-dir so C-Chain EVM + zk/quantum/ threshold/bridge/dex VMs load (mirrors luxd-boot.sh) - fix port allocator feedback loop that overflowed host ports past 65535
This commit is contained in:
@@ -69,18 +69,20 @@ CHAIN_IMAGES = {
|
||||
"blast": {
|
||||
"execution": {"blast": "blastio/blast-geth:latest"},
|
||||
},
|
||||
# ============ HANZO ECOSYSTEM (Lux-based) ============
|
||||
# ============ LUX ECOSYSTEM (luxd — Lux, Zoo, Pars, Hanzo) ============
|
||||
# All four run the same luxd node (ghcr.io/luxfi/node). Only the primary
|
||||
# network-id and genesis differ; Zoo/Pars/Hanzo are Lux-based sovereign L1s.
|
||||
"lux": {
|
||||
"execution": {"luxd": "luxfi/luxd:latest"},
|
||||
"execution": {"luxd": "ghcr.io/luxfi/node:latest"},
|
||||
},
|
||||
"zoo": {
|
||||
"execution": {"luxd": "luxfi/luxd:latest"}, # Zoo subnet on Lux
|
||||
"execution": {"luxd": "ghcr.io/luxfi/node:latest"}, # Zoo: Lux-based sovereign L1
|
||||
},
|
||||
"pars": {
|
||||
"execution": {"luxd": "luxfi/luxd:latest"}, # Pars subnet on Lux
|
||||
"execution": {"luxd": "ghcr.io/luxfi/node:latest"}, # Pars: Lux-based sovereign L1
|
||||
},
|
||||
"hanzo": {
|
||||
"execution": {"luxd": "luxfi/luxd:latest"}, # Hanzo subnet on Lux
|
||||
"execution": {"luxd": "ghcr.io/luxfi/node:latest"}, # Hanzo: Lux-based sovereign L1
|
||||
},
|
||||
# ============ MAJOR L1s ============
|
||||
"bitcoin": {
|
||||
@@ -240,10 +242,10 @@ CHAIN_PORTS = {
|
||||
"mantle": {"rpc": 8545, "ws": 8546},
|
||||
"blast": {"rpc": 8545, "ws": 8546},
|
||||
# Hanzo ecosystem
|
||||
"lux": {"rpc": 9650, "ws": 9650, "p2p": 9651},
|
||||
"zoo": {"rpc": 9650, "ws": 9650, "p2p": 9651},
|
||||
"pars": {"rpc": 9650, "ws": 9650, "p2p": 9651},
|
||||
"hanzo": {"rpc": 9650, "ws": 9650, "p2p": 9651},
|
||||
"lux": {"rpc": 9630, "ws": 9630, "p2p": 9631},
|
||||
"zoo": {"rpc": 9630, "ws": 9630, "p2p": 9631},
|
||||
"pars": {"rpc": 9630, "ws": 9630, "p2p": 9631},
|
||||
"hanzo": {"rpc": 9630, "ws": 9630, "p2p": 9631},
|
||||
# Major L1s
|
||||
"bitcoin": {"rpc": 8332, "p2p": 8333},
|
||||
"solana": {"rpc": 8899, "ws": 8900, "p2p": 8001},
|
||||
@@ -374,7 +376,12 @@ def allocate_ports() -> Dict[str, int]:
|
||||
if bindings:
|
||||
for binding in bindings:
|
||||
host_port = int(binding.get("HostPort", 0))
|
||||
if host_port >= _port_counter["rpc"]:
|
||||
# Only seed the counter from the RPC/ws range.
|
||||
# High p2p/beacon ports (30303+, 19000+) must not
|
||||
# drive the counter up — otherwise each node's p2p
|
||||
# port feeds back and inflates the next allocation
|
||||
# until it overflows 65535.
|
||||
if _port_counter["rpc"] <= host_port < 30000:
|
||||
_port_counter["rpc"] = host_port + 10
|
||||
_port_counter["ws"] = host_port + 11
|
||||
except Exception:
|
||||
@@ -820,10 +827,10 @@ async def start_node_container(node_id: str, node: dict):
|
||||
_nodes[node_id]["container_id"] = exec_container.id[:12]
|
||||
_nodes[node_id]["containers"] = [c.id[:12] for c in containers_created]
|
||||
|
||||
# ============ LUX ECOSYSTEM (Lux, Zoo, Pars, Hanzo) ============
|
||||
# ============ LUX ECOSYSTEM (luxd — Lux, Zoo, Pars, Hanzo) ============
|
||||
elif chain in ["lux", "zoo", "pars", "hanzo"]:
|
||||
exec_images = chain_images.get("execution", {})
|
||||
image = exec_images.get("luxd", "luxfi/luxd:latest")
|
||||
image = exec_images.get("luxd", "ghcr.io/luxfi/node:latest")
|
||||
|
||||
try:
|
||||
client.images.get(image)
|
||||
@@ -835,47 +842,60 @@ async def start_node_container(node_id: str, node: dict):
|
||||
try:
|
||||
old = client.containers.get(container_name)
|
||||
old.remove(force=True)
|
||||
except:
|
||||
except docker.errors.NotFound:
|
||||
pass
|
||||
|
||||
# Configure luxd based on network
|
||||
lux_network_id = "mainnet" if network == "mainnet" else "fuji" if network == "testnet" else "local"
|
||||
# Canonical Lux primary network-id (matches luxd-boot.sh):
|
||||
# localnet=1337, devnet=3, testnet=2, mainnet=1. Zoo/Pars/Hanzo are
|
||||
# Lux-based sovereign L1s — same luxd boot; genesis selects the chain.
|
||||
net_id = {"local": 1337, "localnet": 1337, "devnet": 3,
|
||||
"testnet": 2, "mainnet": 1}.get(network, 1337)
|
||||
|
||||
# For local development, use special config
|
||||
if network == "local":
|
||||
lux_cmd = [
|
||||
"--network-id=local",
|
||||
"--http-host=0.0.0.0",
|
||||
"--http-port=9650",
|
||||
"--staking-enabled=false",
|
||||
"--db-type=memdb",
|
||||
# luxd serves C-Chain HTTP on 9630, staking on 9631 (not 9650).
|
||||
# Custom VM plugins load from --plugin-dir (mount .so into /data/plugins).
|
||||
lux_cmd = [
|
||||
f"--network-id={net_id}",
|
||||
"--http-host=0.0.0.0",
|
||||
"--http-port=9630",
|
||||
"--staking-port=9631",
|
||||
"--data-dir=/data",
|
||||
"--plugin-dir=/data/plugins",
|
||||
]
|
||||
# Single-node local/dev: run without a peer quorum. Real staking keys
|
||||
# under /data/staking are picked up automatically when present (prod).
|
||||
if network in ("local", "localnet", "devnet"):
|
||||
lux_cmd += [
|
||||
"--sybil-protection-enabled=false",
|
||||
"--network-health-min-conn-peers=0",
|
||||
"--skip-bootstrap=true",
|
||||
]
|
||||
else:
|
||||
lux_cmd = [
|
||||
f"--network-id={lux_network_id}",
|
||||
"--http-host=0.0.0.0",
|
||||
"--http-port=9650",
|
||||
"--public-ip-resolution-service=opendns",
|
||||
]
|
||||
|
||||
# Add subnet-specific flags for Zoo/Pars/Hanzo
|
||||
if chain in ["zoo", "pars", "hanzo"]:
|
||||
# These would have subnet-specific configs
|
||||
lux_cmd.extend([
|
||||
"--track-subnets=", # Add actual subnet IDs for production
|
||||
])
|
||||
lux_cmd.append("--public-ip-resolution-service=opendns")
|
||||
|
||||
# luxd loads VMs from --plugin-dir. The C-Chain EVM ships as a plugin
|
||||
# (.so named by vmID under /luxd/build/plugins); custom VM plugins drop
|
||||
# in the same dir. Stage the bundled plugins into the data plugin dir,
|
||||
# then exec luxd — same shape as the canonical luxd-boot.sh. The image
|
||||
# Cmd is ["./luxd"] with no Entrypoint, so we wrap in sh -c.
|
||||
luxd_argv = " ".join(lux_cmd)
|
||||
stage = "mkdir -p /data/plugins && cp -n /luxd/build/plugins/* /data/plugins/ 2>/dev/null; "
|
||||
# Publish RPC always; publish staking only if it maps to a valid host
|
||||
# port (guard against an out-of-range allocation).
|
||||
lux_port_map = {"9630/tcp": ports["rpc"]}
|
||||
staking_host = ports.get("p2p") or (ports["rpc"] + 1)
|
||||
if 1024 < staking_host <= 65535:
|
||||
lux_port_map["9631/tcp"] = staking_host
|
||||
container = client.containers.run(
|
||||
image,
|
||||
command=lux_cmd,
|
||||
entrypoint=["/bin/sh", "-c"],
|
||||
# Single-list element: the whole script is one argv to `sh -c`
|
||||
# (a bare string would be word-split by docker-py).
|
||||
command=[f"{stage}exec /luxd/build/luxd {luxd_argv}"],
|
||||
name=container_name,
|
||||
detach=True,
|
||||
ports={
|
||||
"9650/tcp": ports["rpc"],
|
||||
"9651/tcp": ports.get("p2p", 9651 + (ports["rpc"] - 9650)),
|
||||
},
|
||||
ports=lux_port_map,
|
||||
volumes={
|
||||
f"bootnode-data-{node_id[:8]}": {"bind": "/root/.luxd", "mode": "rw"},
|
||||
f"bootnode-data-{node_id[:8]}": {"bind": "/data", "mode": "rw"},
|
||||
},
|
||||
network=network_name,
|
||||
restart_policy={"Name": "unless-stopped"},
|
||||
|
||||
Reference in New Issue
Block a user