737 lines
29 KiB
Makefile
737 lines
29 KiB
Makefile
# Lux Universe Makefile
|
|
# 5-node networks (mainnet + testnet + devnet) + services
|
|
#
|
|
# Architecture:
|
|
# - Nodes: Run locally via `lux cli` (not Docker)
|
|
# - Services: Run via Docker (explorers, exchange, bridge, graph-node)
|
|
#
|
|
# Quick start:
|
|
# make start network=main # Start mainnet
|
|
# make start network=test # Start testnet
|
|
# make start network=dev # Start devnet
|
|
# make stop network=main # Stop mainnet
|
|
# make status # Show all status
|
|
|
|
SHELL := /bin/bash
|
|
.DEFAULT_GOAL := help
|
|
|
|
# Colors
|
|
RESET := \033[0m
|
|
BOLD := \033[1m
|
|
GREEN := \033[32m
|
|
YELLOW := \033[33m
|
|
BLUE := \033[34m
|
|
RED := \033[31m
|
|
|
|
# Paths
|
|
STATE_DIR := $(HOME)/work/lux/state
|
|
GENESIS_DIR := $(HOME)/work/lux/genesis
|
|
|
|
# Network parameter (REQUIRED for network operations)
|
|
# Usage: make start network=main
|
|
network ?=
|
|
|
|
# Normalize short forms
|
|
ifeq ($(network),main)
|
|
override network := mainnet
|
|
endif
|
|
ifeq ($(network),test)
|
|
override network := testnet
|
|
endif
|
|
ifeq ($(network),dev)
|
|
override network := devnet
|
|
endif
|
|
|
|
# Port configuration per network
|
|
# Mainnet: 9630-9638, Testnet: 9640-9648
|
|
ifeq ($(network),mainnet)
|
|
HTTP_PORT := 9630
|
|
STAKING_PORT := 9631
|
|
EXPLORER_PORT := 4000
|
|
CHAIN_ID := 96369
|
|
ZOO_CHAIN_ID := 200200
|
|
else ifeq ($(network),testnet)
|
|
HTTP_PORT := 9640
|
|
STAKING_PORT := 9641
|
|
EXPLORER_PORT := 4001
|
|
CHAIN_ID := 96368
|
|
ZOO_CHAIN_ID := 200201
|
|
else
|
|
HTTP_PORT := 9650
|
|
STAKING_PORT := 9651
|
|
EXPLORER_PORT := 4002
|
|
CHAIN_ID := 1337
|
|
ZOO_CHAIN_ID := 1338
|
|
endif
|
|
|
|
# Sibling-clone manifest (REPOS.yaml) replaces .gitmodules.
|
|
# Each Lux ecosystem repo lives at $(HOME)/work/lux/<name> as a free-standing
|
|
# sibling clone pinned to a semver tag — never a nested submodule.
|
|
# Helper: scripts/repos.sh {init,update,list} (reads REPOS.yaml via yq).
|
|
REPOS_HELPER := $(realpath $(dir $(lastword $(MAKEFILE_LIST))))/scripts/repos.sh
|
|
|
|
##@ Quick Start
|
|
|
|
# Binaries
|
|
LUXD := $(HOME)/work/lux/node/build/luxd
|
|
ZOOD := $(HOME)/work/zoo/node/build/zood
|
|
HANZOD := $(HOME)/work/hanzo/node/target/release/hanzod
|
|
PLUGIN_DIR := $(HOME)/.lux/plugins/current
|
|
LOCAL_DIR := /tmp/lux-localnet
|
|
LIGHT_MNEMONIC := light light light light light light light light light light light energy
|
|
|
|
# VM IDs
|
|
ZOO_VMID := 2n2njofjYvece8gZWCNnc1mqkcqfW6kbrhPRZPVzwxrSQrQ4gE
|
|
HANZO_VMID := 2CwRhy6P6fQyn3JtZW68BFvn2nRwZ4Z8iar8EEeeLpGKmn5XRT
|
|
|
|
.PHONY: chain
|
|
chain: plugins ## Start just the blockchain (luxd + VM plugins)
|
|
|
|
.PHONY: up
|
|
up: chain ## Start full local universe (chain + services)
|
|
@echo "$(BOLD)Starting Lux localnet (luxd --dev)...$(RESET)"
|
|
@rm -rf $(LOCAL_DIR) && mkdir -p $(LOCAL_DIR)
|
|
@LIGHT_MNEMONIC="$(LIGHT_MNEMONIC)" $(LUXD) --dev \
|
|
--http-host=127.0.0.1 --http-port=9660 \
|
|
--data-dir=$(LOCAL_DIR) \
|
|
--plugin-dir=$(PLUGIN_DIR) \
|
|
--log-level=error 2>/dev/null &
|
|
@sleep 6
|
|
@echo "$(GREEN)luxd running on http://127.0.0.1:9660$(RESET)"
|
|
@curl -s http://127.0.0.1:9660/v1/info -X POST -H 'Content-Type: application/json' \
|
|
-d '{"jsonrpc":"2.0","id":1,"method":"info.getNodeID"}' 2>/dev/null | \
|
|
python3 -c "import sys,json; r=json.load(sys.stdin)['result']; print(' NodeID: ' + r['nodeID'])" 2>/dev/null || true
|
|
@echo "$(GREEN)VM plugins: zoo-evm, hanzo-evm, lux-evm$(RESET)"
|
|
@echo "$(GREEN)Chains: P, X, C, Z$(RESET)"
|
|
@echo ""
|
|
@echo "$(BOLD)Endpoints:$(RESET)"
|
|
@echo " P-Chain: http://127.0.0.1:9660/v1/chain/P"
|
|
@echo " X-Chain: http://127.0.0.1:9660/v1/chain/X"
|
|
@echo " C-Chain: http://127.0.0.1:9660/v1/chain/C/rpc"
|
|
@echo " Z-Chain: http://127.0.0.1:9660/v1/chain/z-chain/rpc"
|
|
@echo ""
|
|
@echo " Funded: 0x9011E888 (from LIGHT_MNEMONIC)"
|
|
@echo " Stop: make down"
|
|
|
|
.PHONY: down
|
|
down: ## Stop local dev network
|
|
@echo "$(BOLD)Stopping localnet...$(RESET)"
|
|
@pkill -f "luxd.*9660" 2>/dev/null || true
|
|
@echo "$(GREEN)Stopped$(RESET)"
|
|
|
|
.PHONY: plugins
|
|
plugins: ## Install VM plugins (zood, hanzod)
|
|
@mkdir -p $(PLUGIN_DIR)
|
|
@if [ ! -f $(ZOOD) ]; then echo "Building zood..." && cd $(HOME)/work/zoo/node && \
|
|
GONOSUMCHECK="*" GONOSUMDB="*" GOPRIVATE="*" go build -o build/zood . 2>/dev/null; fi
|
|
@if [ ! -f $(HANZOD) ]; then echo "Building hanzod..." && cd $(HOME)/work/hanzo/evm && \
|
|
cargo build --release -p hanzo-node 2>/dev/null; fi
|
|
@ln -sf $(ZOOD) $(PLUGIN_DIR)/$(ZOO_VMID) 2>/dev/null || true
|
|
@ln -sf $(HANZOD) $(PLUGIN_DIR)/$(HANZO_VMID) 2>/dev/null || true
|
|
|
|
.PHONY: all
|
|
all: ## Start all networks + services
|
|
@$(MAKE) -s start network=mainnet &
|
|
@$(MAKE) -s start network=testnet &
|
|
@$(MAKE) -s start network=devnet &
|
|
@wait
|
|
@$(MAKE) -s services
|
|
@echo "$(GREEN)$(BOLD)Lux Universe running (mainnet/testnet/devnet)!$(RESET)"
|
|
@$(MAKE) -s status-all
|
|
|
|
.PHONY: stop-all
|
|
stop-all: ## Stop everything
|
|
@$(MAKE) -s stop network=mainnet
|
|
@$(MAKE) -s stop network=testnet
|
|
@$(MAKE) -s stop network=devnet
|
|
@$(MAKE) -s stop-services
|
|
|
|
##@ Sibling Repos (REPOS.yaml — no submodules)
|
|
|
|
.PHONY: init
|
|
init: ## Clone every sibling repo at its pinned semver (~/work/lux/<name>)
|
|
@echo "$(BOLD)Cloning sibling repos at pinned semver tags...$(RESET)"
|
|
@$(REPOS_HELPER) init
|
|
|
|
.PHONY: update
|
|
update: ## Fetch + checkout pinned tag (all repos, or one via name=<repo>)
|
|
@echo "$(BOLD)Updating siblings to pinned tags...$(RESET)"
|
|
@$(REPOS_HELPER) update $(name)
|
|
|
|
.PHONY: sync
|
|
sync: init ## Alias for init — ensure all siblings cloned at pinned tag
|
|
|
|
.PHONY: list
|
|
list: ## List sibling repos + pinned tags from REPOS.yaml
|
|
@$(REPOS_HELPER) list
|
|
|
|
##@ Network Management
|
|
|
|
.PHONY: start
|
|
start: ## Start network (network=main|test|dev required)
|
|
@if [ "$(network)" != "mainnet" ] && [ "$(network)" != "testnet" ] && [ "$(network)" != "devnet" ]; then \
|
|
echo "$(RED)Error: network=main|test|dev required$(RESET)"; exit 1; fi
|
|
@echo "$(BOLD)Starting $(network) (port $(HTTP_PORT))...$(RESET)"
|
|
@RUN_E2E=true lux network start --$(network) 2>&1 | tail -5
|
|
@sleep 3
|
|
@$(MAKE) -s health network=$(network)
|
|
@$(MAKE) -s track network=$(network)
|
|
|
|
.PHONY: stop
|
|
stop: ## Stop network (network=main|test|dev required)
|
|
@if [ "$(network)" != "mainnet" ] && [ "$(network)" != "testnet" ] && [ "$(network)" != "devnet" ]; then \
|
|
echo "$(RED)Error: network=main|test|dev required$(RESET)"; exit 1; fi
|
|
@echo "$(BOLD)Stopping $(network)...$(RESET)"
|
|
@RUN_E2E=true lux network stop --$(network) --force 2>/dev/null || true
|
|
@echo "$(GREEN)$(network) stopped$(RESET)"
|
|
|
|
.PHONY: restart
|
|
restart: ## Restart network (network=main|test|dev required)
|
|
@if [ "$(network)" != "mainnet" ] && [ "$(network)" != "testnet" ] && [ "$(network)" != "devnet" ]; then \
|
|
echo "$(RED)Error: network=main|test|dev required$(RESET)"; exit 1; fi
|
|
@$(MAKE) -s stop network=$(network)
|
|
@$(MAKE) -s start network=$(network)
|
|
|
|
.PHONY: clean
|
|
clean: ## Clean network state (network=main|test|dev required)
|
|
@if [ "$(network)" != "mainnet" ] && [ "$(network)" != "testnet" ] && [ "$(network)" != "devnet" ]; then \
|
|
echo "$(RED)Error: network=main|test|dev required$(RESET)"; exit 1; fi
|
|
@echo "$(YELLOW)Cleaning $(network) state...$(RESET)"
|
|
@RUN_E2E=true lux network clean --$(network) 2>/dev/null || true
|
|
@echo "$(GREEN)$(network) state cleaned$(RESET)"
|
|
|
|
.PHONY: clean-all
|
|
clean-all: ## Clean ALL network state (all networks)
|
|
@echo "$(YELLOW)Cleaning all network state...$(RESET)"
|
|
@RUN_E2E=true lux network clean --mainnet 2>/dev/null || true
|
|
@RUN_E2E=true lux network clean --testnet 2>/dev/null || true
|
|
@RUN_E2E=true lux network clean --devnet 2>/dev/null || true
|
|
@rm -rf $(HOME)/.lux/runs/* 2>/dev/null || true
|
|
@echo "$(GREEN)All network state cleaned$(RESET)"
|
|
|
|
##@ Health Checks
|
|
|
|
.PHONY: health
|
|
health: ## Check network health (network=main|test|dev required)
|
|
@if [ "$(network)" != "mainnet" ] && [ "$(network)" != "testnet" ] && [ "$(network)" != "devnet" ]; then \
|
|
echo "$(RED)Error: network=main|test|dev required$(RESET)"; exit 1; fi
|
|
@echo "$(BOLD)$(network) Health ($(HTTP_PORT)-$$(($(HTTP_PORT)+8))):$(RESET)"
|
|
@for i in 0 2 4 6 8; do \
|
|
port=$$(($(HTTP_PORT)+$$i)); \
|
|
healthy=$$(curl -s -m 1 http://127.0.0.1:$$port/v1/health 2>/dev/null | jq -r '.healthy // false' 2>/dev/null || echo "false"); \
|
|
if [ "$$healthy" = "true" ]; then \
|
|
echo " Node $$port: $(GREEN)healthy$(RESET)"; \
|
|
else \
|
|
echo " Node $$port: $(YELLOW)offline$(RESET)"; \
|
|
fi; \
|
|
done
|
|
|
|
.PHONY: track
|
|
track: ## Ensure tracked chains are deployed (network=main|test|dev required)
|
|
@if [ "$(network)" != "mainnet" ] && [ "$(network)" != "testnet" ] && [ "$(network)" != "devnet" ]; then \
|
|
echo "$(RED)Error: network=main|test|dev required$(RESET)"; exit 1; fi
|
|
@bash scripts/ensure-tracked-chains.sh $(network) $(STATE_DIR)
|
|
|
|
##@ Chain Import
|
|
|
|
# RLP file paths per network
|
|
ifeq ($(network),mainnet)
|
|
RLP_DIR := lux-mainnet
|
|
RLP_CCHAIN := lux-mainnet-96369.rlp
|
|
RLP_ZOO := zoo-mainnet-200200.rlp
|
|
ZOO_BC := zoo
|
|
else ifeq ($(network),testnet)
|
|
RLP_DIR := lux-testnet
|
|
RLP_CCHAIN := lux-testnet-96368.rlp
|
|
RLP_ZOO := zoo-testnet-200201.rlp
|
|
ZOO_BC := zootest
|
|
endif
|
|
|
|
.PHONY: import
|
|
import: ## Import chains (network=main|test required)
|
|
@if [ "$(network)" != "mainnet" ] && [ "$(network)" != "testnet" ]; then \
|
|
echo "$(RED)Error: network=main|test required$(RESET)"; exit 1; fi
|
|
@echo "$(BOLD)Importing $(network) chains...$(RESET)"
|
|
@echo " C-Chain ($(CHAIN_ID))..."
|
|
@curl -s -X POST "http://127.0.0.1:$(HTTP_PORT)/v1/chain/C/rpc" -H "Content-Type: application/json" \
|
|
-d '{"jsonrpc":"2.0","method":"admin_importChain","params":["$(STATE_DIR)/rlp/$(RLP_DIR)/$(RLP_CCHAIN)"],"id":1}' 2>/dev/null | jq -r '.result // .error // "sent"' &
|
|
@echo " Zoo ($(ZOO_CHAIN_ID))..."
|
|
@if [ -f "$(STATE_DIR)/rlp/zoo-$(network)/$(RLP_ZOO)" ]; then \
|
|
curl -s -X POST "http://127.0.0.1:$(HTTP_PORT)/v1/chain/$(ZOO_BC)/rpc" -H "Content-Type: application/json" \
|
|
-d '{"jsonrpc":"2.0","method":"admin_importChain","params":["$(STATE_DIR)/rlp/zoo-$(network)/$(RLP_ZOO)"],"id":1}' 2>/dev/null | jq -r '.result // .error // "sent"' & \
|
|
fi
|
|
@wait
|
|
@echo "$(GREEN)$(network) import started$(RESET)"
|
|
|
|
##@ Snapshot & Resume
|
|
|
|
.PHONY: snapshot
|
|
snapshot: ## Snapshot network (network=main|test required, name=<name>)
|
|
@if [ "$(network)" != "mainnet" ] && [ "$(network)" != "testnet" ]; then \
|
|
echo "$(RED)Error: network=main|test required$(RESET)"; exit 1; fi
|
|
@snap_name="$(name)"; \
|
|
if [ -z "$$snap_name" ]; then snap_name="$(network)-$$(date +%Y%m%d-%H%M%S)"; fi; \
|
|
echo "$(BOLD)Snapshotting $(network) as '$$snap_name'...$(RESET)"; \
|
|
RUN_E2E=true lux network stop --$(network) --force --snapshot-name "$$snap_name" 2>/dev/null || true; \
|
|
echo "$(GREEN)$(network) snapshot '$$snap_name' saved$(RESET)"
|
|
|
|
.PHONY: resume
|
|
resume: ## Resume network from snapshot (network=main|test required, name=<name>)
|
|
@if [ "$(network)" != "mainnet" ] && [ "$(network)" != "testnet" ]; then \
|
|
echo "$(RED)Error: network=main|test required$(RESET)"; exit 1; fi
|
|
@if [ -z "$(name)" ]; then \
|
|
echo "$(BOLD)Available $(network) snapshots:$(RESET)"; \
|
|
ls -1 $(HOME)/.lux/snapshots 2>/dev/null | grep $(network) || echo " None"; \
|
|
exit 1; \
|
|
fi
|
|
@echo "$(BOLD)Resuming $(network) from '$(name)'...$(RESET)"
|
|
@RUN_E2E=true lux network start --$(network) --snapshot-name "$(name)"
|
|
@$(MAKE) -s health network=$(network)
|
|
|
|
.PHONY: snapshots
|
|
snapshots: ## List all snapshots
|
|
@echo "$(BOLD)Available snapshots:$(RESET)"
|
|
@ls -1 $(HOME)/.lux/snapshots 2>/dev/null || echo " None"
|
|
|
|
##@ Bootstrap & Snapshot Management
|
|
|
|
# Bootstrap source directory
|
|
BOOTSTRAP_DIR := $(STATE_DIR)/snapshots
|
|
|
|
.PHONY: bootstrap
|
|
bootstrap: ## Bootstrap network from snapshot (network=main|test|dev required)
|
|
@if [ "$(network)" != "mainnet" ] && [ "$(network)" != "testnet" ] && [ "$(network)" != "devnet" ]; then \
|
|
echo "$(RED)Error: network=main|test|dev required$(RESET)"; exit 1; fi
|
|
@echo "$(BOLD)Bootstrapping $(network)...$(RESET)"
|
|
@mkdir -p $(HOME)/.lux/snapshots
|
|
@if [ "$(network)" = "mainnet" ]; then \
|
|
BOOTSTRAP_NAME="mainnet-bootstrap"; \
|
|
elif [ "$(network)" = "testnet" ]; then \
|
|
BOOTSTRAP_NAME="testnet-bootstrap"; \
|
|
else \
|
|
BOOTSTRAP_NAME="devnet-bootstrap"; \
|
|
fi;
|
|
@if [ -d "$(BOOTSTRAP_DIR)/$$BOOTSTRAP_NAME" ]; then \
|
|
echo "$(BLUE)Extracting bootstrap snapshot...$(RESET)"; \
|
|
cd $(HOME)/.lux/snapshots && \
|
|
cat "$(BOOTSTRAP_DIR)/$$BOOTSTRAP_NAME/$(network).tar.gz.*" > $$BOOTSTRAP_NAME.tar.gz 2>/dev/null || true; \
|
|
if [ -f "$$BOOTSTRAP_NAME.tar.gz" ]; then \
|
|
tar -xzf $$BOOTSTRAP_NAME.tar.gz && \
|
|
rm -f $$BOOTSTRAP_NAME.tar.gz; \
|
|
elif [ -d "$$BOOTSTRAP_NAME" ]; then \
|
|
echo "$(YELLOW)Already extracted$(RESET)"; \
|
|
else \
|
|
echo "$(RED)Error: Bootstrap extraction failed$(RESET)"; exit 1; \
|
|
fi;
|
|
# Move extracted data to network directory
|
|
if [ -d "$$BOOTSTRAP_NAME/run_*" ]; then \
|
|
LATEST_RUN=$(ls -td $$BOOTSTRAP_NAME/run_* | head -1); \
|
|
echo "$(BLUE)Setting up network from $$LATEST_RUN...$(RESET)"; \
|
|
mkdir -p $(HOME)/.lux/$(network); \
|
|
for node_num in 1 2 3 4 5; do \
|
|
if [ -d "$$LATEST_RUN/node$$node_num" ]; then \
|
|
cp -r "$$LATEST_RUN/node$$node_num" "$(HOME)/.lux/$(network)/"; \
|
|
fi; \
|
|
done; \
|
|
cp -f "$$LATEST_RUN/prometheus.yaml" "$(HOME)/.lux/$(network)/" 2>/dev/null || true; \
|
|
ln -sf "$(basename $$LATEST_RUN)" "$$BOOTSTRAP_NAME/current"; \
|
|
echo "$(GREEN)$(network) bootstrap setup complete$(RESET)"; \
|
|
else \
|
|
echo "$(RED)Error: No run data found in bootstrap$(RESET)"; exit 1; \
|
|
fi; \
|
|
else \
|
|
echo "$(RED)Error: Bootstrap not found at $(BOOTSTRAP_DIR)/$$BOOTSTRAP_NAME$(RESET)"; \
|
|
echo "$(YELLOW)Try: git lfs pull --include='state/snapshots/$(network)-bootstrap/*'$(RESET)"; \
|
|
exit 1; \
|
|
fi
|
|
|
|
.PHONY: bootstrap-start
|
|
bootstrap-start: ## Bootstrap and start network (network=main|test|dev required)
|
|
@$(MAKE) -s bootstrap network=$(network)
|
|
@echo "$(BOLD)Starting $(network)...$(RESET)"
|
|
@RUN_E2E=true lux network start --$(network)
|
|
@$(MAKE) -s health network=$(network)
|
|
@$(MAKE) -s track network=$(network)
|
|
|
|
.PHONY: bootstrap-clean
|
|
bootstrap-clean: ## Clean bootstrap data
|
|
@echo "$(BOLD)Cleaning bootstrap data...$(RESET)"
|
|
@rm -rf $(HOME)/.lux/snapshots/*-bootstrap*
|
|
@echo "$(GREEN)Bootstrap data cleaned$(RESET)"
|
|
|
|
.PHONY: snapshot-save
|
|
snapshot-save: ## Save network snapshot (network=main|test|dev required, name=<name>)
|
|
@if [ "$(network)" != "mainnet" ] && [ "$(network)" != "testnet" ] && [ "$(network)" != "devnet" ]; then \
|
|
echo "$(RED)Error: network=main|test|dev required$(RESET)"; exit 1; fi
|
|
@snap_name="$(name)"; \
|
|
if [ -z "$$snap_name" ]; then snap_name="$(network)-$$(date +%Y%m%d-%H%M%S)"; fi; \
|
|
mkdir -p $(HOME)/.lux/snapshots; \
|
|
echo "$(BOLD)Saving $(network) snapshot '$$snap_name'...$(RESET)"; \
|
|
RUN_E2E=true lux network stop --$(network) --force 2>/dev/null || true; \
|
|
cp -r $(HOME)/.lux/$(network) $(HOME)/.lux/snapshots/$$snap_name && \
|
|
tar -czf $(HOME)/.lux/snapshots/$$snap_name.tar.gz -C $(HOME)/.lux/snapshots $$snap_name && \
|
|
rm -rf $(HOME)/.lux/snapshots/$$snap_name && \
|
|
echo "$(GREEN)$(network) snapshot '$$snap_name' saved$(RESET)"
|
|
|
|
.PHONY: snapshot-load
|
|
snapshot-load: ## Load network snapshot (network=main|test|dev required, name=<name>)
|
|
@if [ "$(network)" != "mainnet" ] && [ "$(network)" != "testnet" ] && [ "$(network)" != "devnet" ]; then \
|
|
echo "$(RED)Error: network=main|test|dev required$(RESET)"; exit 1; fi
|
|
@if [ -z "$(name)" ]; then \
|
|
echo "$(BOLD)Available $(network) snapshots:$(RESET)"; \
|
|
ls -1 $(HOME)/.lux/snapshots 2>/dev/null | grep $(network) || echo " None"; \
|
|
exit 1; \
|
|
fi
|
|
@echo "$(BOLD)Loading $(network) from '$(name)'...$(RESET)"
|
|
@RUN_E2E=true lux network stop --$(network) --force 2>/dev/null || true; \
|
|
mkdir -p $(HOME)/.lux/$(network).backup.$$(date +%Y%m%d-%H%M%S) && \
|
|
mv $(HOME)/.lux/$(network) $(HOME)/.lux/$(network).backup.$$(date +%Y%m%d-%H%M%S) 2>/dev/null || true; \
|
|
tar -xzf $(HOME)/.lux/snapshots/$(name).tar.gz -C $(HOME)/.lux && \
|
|
mv $(HOME)/.lux/snapshots/$(name) $(HOME)/.lux/$(network) && \
|
|
echo "$(GREEN)$(network) snapshot '$(name)' loaded$(RESET)"
|
|
|
|
.PHONY: snapshot-list
|
|
snapshot-list: ## List all snapshots
|
|
@echo "$(BOLD)Available snapshots:$(RESET)"
|
|
@ls -1 $(HOME)/.lux/snapshots 2>/dev/null | sed 's/\.tar\.gz$$//' || echo " None"
|
|
|
|
.PHONY: snapshot-clean
|
|
snapshot-clean: ## Clean all snapshots
|
|
@echo "$(BOLD)Cleaning all snapshots...$(RESET)"
|
|
@rm -rf $(HOME)/.lux/snapshots/*
|
|
@echo "$(GREEN)All snapshots cleaned$(RESET)"
|
|
|
|
##@ AMM Testing
|
|
|
|
# AMM network name mapping
|
|
ifeq ($(network),mainnet)
|
|
AMM_NETWORK := lux
|
|
AMM_ZOO := zoo
|
|
else ifeq ($(network),testnet)
|
|
AMM_NETWORK := lux-testnet
|
|
AMM_ZOO := zoo
|
|
endif
|
|
|
|
.PHONY: amm
|
|
amm: ## Test AMM on C-chain (network=main|test required)
|
|
@if [ "$(network)" != "mainnet" ] && [ "$(network)" != "testnet" ]; then \
|
|
echo "$(RED)Error: network=main|test required$(RESET)"; exit 1; fi
|
|
@echo "$(BOLD)Testing AMM on $(network) C-chain ($(CHAIN_ID))...$(RESET)"
|
|
@lux amm status --network $(AMM_NETWORK) --rpc http://127.0.0.1:$(HTTP_PORT)/v1/chain/C/rpc 2>&1 | head -20
|
|
|
|
.PHONY: amm-zoo
|
|
amm-zoo: ## Test AMM on Zoo (network=main|test required)
|
|
@if [ "$(network)" != "mainnet" ] && [ "$(network)" != "testnet" ]; then \
|
|
echo "$(RED)Error: network=main|test required$(RESET)"; exit 1; fi
|
|
@echo "$(BOLD)Testing AMM on $(network) Zoo ($(ZOO_CHAIN_ID))...$(RESET)"
|
|
@lux amm status --network $(AMM_ZOO) --rpc http://127.0.0.1:$(HTTP_PORT)/v1/chain/$(ZOO_BC)/rpc 2>&1 | head -20
|
|
|
|
##@ Docker Services
|
|
|
|
.PHONY: services
|
|
services: ## Start all Docker services
|
|
@echo "$(BOLD)Starting Docker services...$(RESET)"
|
|
docker compose up -d
|
|
@echo "$(GREEN)Services started!$(RESET)"
|
|
@$(MAKE) -s service-status
|
|
|
|
.PHONY: stop-services
|
|
stop-services: ## Stop all Docker services
|
|
@echo "$(BOLD)Stopping Docker services...$(RESET)"
|
|
docker compose down
|
|
@echo "$(GREEN)Services stopped$(RESET)"
|
|
|
|
.PHONY: service-status
|
|
service-status: ## Show Docker service status
|
|
@echo "$(BOLD)Docker Services:$(RESET)"
|
|
@docker compose ps --format "table {{.Name}}\t{{.Status}}\t{{.Ports}}" 2>/dev/null || echo " No services running"
|
|
|
|
.PHONY: service-logs
|
|
service-logs: ## Tail Docker service logs
|
|
docker compose logs -f --tail=100
|
|
|
|
.PHONY: explorers
|
|
explorers: ## Start block explorers
|
|
docker compose up -d explorer-lux explorer-zoo
|
|
|
|
.PHONY: exchange
|
|
exchange: ## Start exchange (DEX)
|
|
docker compose up -d exchange
|
|
|
|
.PHONY: bridge
|
|
bridge: ## Start bridge
|
|
docker compose up -d bridge
|
|
|
|
.PHONY: graph
|
|
graph: ## Start Graph Protocol
|
|
docker compose up -d graph-node-lux
|
|
|
|
##@ Status
|
|
|
|
.PHONY: status
|
|
status: ## Show network status (network=main|test|dev required, or status-all for all)
|
|
@if [ "$(network)" != "mainnet" ] && [ "$(network)" != "testnet" ] && [ "$(network)" != "devnet" ]; then \
|
|
echo "$(RED)Error: network=main|test|dev required (or use status-all)$(RESET)"; exit 1; fi
|
|
@echo "$(BOLD)═══ $(network) ($(HTTP_PORT)) ═══$(RESET)"
|
|
@$(MAKE) -s health network=$(network)
|
|
@echo ""
|
|
@cblock=$$(curl -s -m 1 -X POST -H "Content-Type: application/json" \
|
|
--data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \
|
|
http://127.0.0.1:$(HTTP_PORT)/v1/chain/C/rpc 2>/dev/null | jq -r '.result // "N/A"' 2>/dev/null); \
|
|
if [ -z "$$cblock" ]; then cblock="N/A"; fi; \
|
|
echo " C-Chain Block: $$cblock"
|
|
@bash scripts/check-tracked-chains.sh $(network) $(HTTP_PORT)
|
|
@echo ""
|
|
@echo "$(BOLD)Endpoints:$(RESET)"
|
|
@echo " C-Chain RPC: http://127.0.0.1:$(HTTP_PORT)/v1/chain/C/rpc"
|
|
@echo " Explorer: http://127.0.0.1:$(EXPLORER_PORT)"
|
|
|
|
.PHONY: status-all
|
|
status-all: ## Show all networks + services status
|
|
@echo "$(BOLD)═══════════════════════════════════════$(RESET)"
|
|
@echo "$(BOLD) LUX UNIVERSE STATUS $(RESET)"
|
|
@echo "$(BOLD)═══════════════════════════════════════$(RESET)"
|
|
@echo ""
|
|
@echo "$(BOLD)═══ MAINNET (9630) ═══$(RESET)"
|
|
@$(MAKE) -s health network=mainnet 2>/dev/null || echo " Mainnet: offline"
|
|
@cblock=$$(curl -s -m 1 -X POST -H "Content-Type: application/json" \
|
|
--data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \
|
|
http://127.0.0.1:9630/v1/chain/C/rpc 2>/dev/null | jq -r '.result // "N/A"' 2>/dev/null); \
|
|
if [ -z "$$cblock" ]; then cblock="N/A"; fi; \
|
|
echo " C-Chain Block: $$cblock"
|
|
@bash scripts/check-tracked-chains.sh mainnet 9630
|
|
@echo ""
|
|
@echo "$(BOLD)═══ TESTNET (9640) ═══$(RESET)"
|
|
@$(MAKE) -s health network=testnet 2>/dev/null || echo " Testnet: offline"
|
|
@cblock=$$(curl -s -m 1 -X POST -H "Content-Type: application/json" \
|
|
--data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \
|
|
http://127.0.0.1:9640/v1/chain/C/rpc 2>/dev/null | jq -r '.result // "N/A"' 2>/dev/null); \
|
|
if [ -z "$$cblock" ]; then cblock="N/A"; fi; \
|
|
echo " C-Chain Block: $$cblock"
|
|
@bash scripts/check-tracked-chains.sh testnet 9640
|
|
@echo ""
|
|
@echo "$(BOLD)═══ DEVNET (9650) ═══$(RESET)"
|
|
@$(MAKE) -s health network=devnet 2>/dev/null || echo " Devnet: offline"
|
|
@cblock=$$(curl -s -m 1 -X POST -H "Content-Type: application/json" \
|
|
--data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \
|
|
http://127.0.0.1:9650/v1/chain/C/rpc 2>/dev/null | jq -r '.result // "N/A"' 2>/dev/null); \
|
|
if [ -z "$$cblock" ]; then cblock="N/A"; fi; \
|
|
echo " C-Chain Block: $$cblock"
|
|
@bash scripts/check-tracked-chains.sh devnet 9650
|
|
@echo ""
|
|
@$(MAKE) -s service-status
|
|
@echo ""
|
|
@echo "$(BOLD)Endpoints:$(RESET)"
|
|
@echo " Mainnet C-Chain: http://127.0.0.1:9630/v1/chain/C/rpc"
|
|
@echo " Testnet C-Chain: http://127.0.0.1:9640/v1/chain/C/rpc"
|
|
@echo " Devnet C-Chain: http://127.0.0.1:9650/v1/chain/C/rpc"
|
|
@echo " Explorer: http://127.0.0.1:4000"
|
|
|
|
##@ Build
|
|
|
|
.PHONY: build
|
|
build: build-node build-cli ## Build core components
|
|
|
|
.PHONY: build-node
|
|
build-node: ## Build lux node
|
|
@echo "$(BOLD)Building node...$(RESET)"
|
|
@if [ -f node/Makefile ]; then $(MAKE) -C node build; \
|
|
else (cd node && go build -o build/luxd ./main); fi
|
|
|
|
.PHONY: build-cli
|
|
build-cli: ## Build lux CLI
|
|
@echo "$(BOLD)Building CLI...$(RESET)"
|
|
@(cd cli && go build -o build/lux ./main)
|
|
|
|
.PHONY: build-evm
|
|
build-evm: ## Build EVM plugin
|
|
@(cd evm && go build -o build/evm ./plugin)
|
|
|
|
.PHONY: build-docker
|
|
build-docker: ## Build Docker images
|
|
docker compose build
|
|
|
|
##@ Testing
|
|
|
|
.PHONY: test
|
|
test: ## Run tests for core components
|
|
@for mod in node geth evm cli; do \
|
|
if [ -f "$$mod/go.mod" ]; then \
|
|
echo "$(BLUE)Testing $$mod...$(RESET)"; \
|
|
(cd $$mod && go test -race -timeout 5m ./...) || exit 1; \
|
|
fi; \
|
|
done
|
|
|
|
##@ E2E Testing (Playwright)
|
|
|
|
# ONE axis: LUX_ENV=local|devnet|testnet|mainnet (default mainnet). Every url,
|
|
# port and chainId is resolved by e2e/env.ts from NETWORKS.yaml — never here.
|
|
# ONE viewport set: projects mobile(390x844) tablet(834x1194) laptop(1440x900),
|
|
# so "mobile and desktop" is the same three frames every run. Narrow a run with
|
|
# `vp=<name>` and a spec with `spec=<path>`.
|
|
# Screenshots (pass AND fail) land in ~/Desktop/lux-e2e/$(LUX_ENV)/.
|
|
LUX_ENV ?= mainnet
|
|
PW := LUX_ENV=$(LUX_ENV) npx playwright test $(if $(vp),--project=$(vp),)
|
|
|
|
.PHONY: e2e
|
|
e2e: ## Run all E2E tests (LUX_ENV=local|devnet|testnet|mainnet, vp=mobile|tablet|laptop)
|
|
@echo "$(BOLD)E2E — LUX_ENV=$(LUX_ENV)$(if $(vp), project=$(vp),) → ~/Desktop/lux-e2e/$(LUX_ENV)$(RESET)"
|
|
@$(PW) $(spec)
|
|
|
|
.PHONY: e2e-mainnet e2e-testnet e2e-devnet e2e-local
|
|
e2e-mainnet: ## Run all E2E against mainnet
|
|
@$(MAKE) -s e2e LUX_ENV=mainnet
|
|
e2e-testnet: ## Run all E2E against testnet
|
|
@$(MAKE) -s e2e LUX_ENV=testnet
|
|
e2e-devnet: ## Run all E2E against devnet
|
|
@$(MAKE) -s e2e LUX_ENV=devnet
|
|
e2e-local: ## Run all E2E against the local stack (make start network=main + ./local/up.sh)
|
|
@$(MAKE) -s e2e LUX_ENV=local
|
|
|
|
.PHONY: e2e-login
|
|
e2e-login: ## Prove sign-in for real (needs LUX_E2E_PASSWORD)
|
|
@if [ -z "$$LUX_E2E_PASSWORD" ]; then \
|
|
echo "$(RED)LUX_E2E_PASSWORD is not set — export it first (never commit it)$(RESET)"; exit 1; fi
|
|
@$(PW) e2e/50-login.spec.ts
|
|
|
|
# ── Is the chain alive ──────────────────────────────────────────────────────
|
|
# The one question nothing in the suite asked until 00-liveness. Gates on the
|
|
# TIP, calibrated against the chain's own recent cadence — never on readiness,
|
|
# which read 5/5 Ready on all fifteen pods while mainnet had been frozen for 59
|
|
# hours. Runs in ~25s; run it first, and believe it over any dashboard.
|
|
.PHONY: e2e-live
|
|
e2e-live: ## Is the chain actually producing blocks? (tip freshness, all 3 networks)
|
|
@$(PW) e2e/00-liveness.spec.ts
|
|
|
|
# ── Every page of every product ─────────────────────────────────────────────
|
|
# Routes come from e2e/routes.ts, so these two targets grow with the products
|
|
# and never with the Makefile.
|
|
.PHONY: e2e-surfaces
|
|
e2e-surfaces: ## Sweep every declared route of every product, anonymously
|
|
@$(PW) e2e/60-surfaces.spec.ts
|
|
|
|
.PHONY: e2e-console
|
|
e2e-console: ## Sweep all 43 lux.cloud dashboard routes SIGNED IN (needs LUX_E2E_PASSWORD)
|
|
@if [ -z "$$LUX_E2E_PASSWORD" ]; then \
|
|
echo "$(RED)LUX_E2E_PASSWORD is not set — the authenticated sweep FAILS rather than"; \
|
|
echo "skipping, because a skipped sweep is the same colour as a passing one$(RESET)"; exit 1; fi
|
|
@$(PW) e2e/61-console.spec.ts
|
|
|
|
.PHONY: e2e-institutional
|
|
e2e-institutional: ## Score the institutional baseline, 27 screens (needs LUX_E2E_PASSWORD)
|
|
@LUX_SHOT_SET=institutional-baseline $(PW) e2e/51-institutional-baseline.spec.ts
|
|
|
|
# The pre-go-live gate: the load-bearing surfaces at all three frames, in
|
|
# minutes rather than hours. `make e2e` runs everything including the very large
|
|
# legacy broker/exchange specs, which are serial within their own file and so
|
|
# dominate a full run.
|
|
.PHONY: e2e-gate
|
|
e2e-gate: ## Run the go-live gate (liveness + surfaces + validators + defi + bridge + dex + login)
|
|
@$(PW) e2e/00-liveness.spec.ts e2e/00-health.spec.ts e2e/01-explorer.spec.ts \
|
|
e2e/08-validator-lifecycle.spec.ts \
|
|
e2e/09-defi-flow.spec.ts e2e/13-bridge-mpc.spec.ts e2e/14-dex-contracts.spec.ts \
|
|
e2e/14-network-independence.spec.ts e2e/16-app-chains.spec.ts \
|
|
e2e/60-surfaces.spec.ts \
|
|
$(if $(LUX_E2E_PASSWORD),e2e/50-login.spec.ts e2e/61-console.spec.ts,)
|
|
|
|
.PHONY: e2e-health
|
|
e2e-health: ## Run health/RPC E2E tests only
|
|
@$(PW) e2e/00-health.spec.ts
|
|
|
|
.PHONY: e2e-explorer
|
|
e2e-explorer: ## Run explorer E2E tests
|
|
@$(PW) e2e/01-explorer.spec.ts
|
|
|
|
.PHONY: e2e-exchange
|
|
e2e-exchange: ## Run exchange E2E tests
|
|
@$(PW) e2e/02-exchange.spec.ts
|
|
|
|
.PHONY: e2e-bridge
|
|
e2e-bridge: ## Run bridge E2E tests
|
|
@$(PW) e2e/03-bridge.spec.ts
|
|
|
|
.PHONY: e2e-staking
|
|
e2e-staking: ## Run staking/delegation E2E tests
|
|
@$(PW) e2e/04-staking.spec.ts
|
|
|
|
.PHONY: e2e-cloud
|
|
e2e-cloud: ## Run cloud bootnode E2E tests
|
|
@$(PW) e2e/05-cloud.spec.ts
|
|
|
|
.PHONY: e2e-wallet
|
|
e2e-wallet: ## Run wallet E2E tests
|
|
@$(PW) e2e/06-wallet.spec.ts
|
|
|
|
.PHONY: e2e-validator
|
|
e2e-validator: ## Run local validator E2E tests (local stack only)
|
|
@$(MAKE) -s e2e LUX_ENV=local spec=e2e/07-validator.spec.ts
|
|
|
|
.PHONY: e2e-install
|
|
e2e-install: ## Install Playwright + browsers
|
|
@npm ci
|
|
@npx playwright install --with-deps chromium
|
|
|
|
.PHONY: e2e-report
|
|
e2e-report: ## Open Playwright HTML report
|
|
@npx playwright show-report
|
|
|
|
.PHONY: e2e-shots
|
|
e2e-shots: ## Open the screenshot directory for this env
|
|
@open ~/Desktop/lux-e2e/$(LUX_ENV) 2>/dev/null || echo "no shots yet for LUX_ENV=$(LUX_ENV)"
|
|
|
|
##@ Development
|
|
|
|
.PHONY: dev
|
|
dev: init all ## Quick dev setup (starts both networks)
|
|
|
|
.PHONY: reset
|
|
reset: ## Reset submodules
|
|
git submodule foreach --recursive git reset --hard
|
|
git submodule update --init --recursive
|
|
|
|
.PHONY: clean-build
|
|
clean-build: ## Clean build artifacts
|
|
@for mod in node geth evm cli; do \
|
|
[ -d "$$mod" ] && (cd $$mod && go clean -cache 2>/dev/null) || true; \
|
|
done
|
|
|
|
.PHONY: fmt
|
|
fmt: ## Format Go code
|
|
@for mod in node geth evm cli consensus; do \
|
|
[ -f "$$mod/go.mod" ] && (cd $$mod && go fmt ./...) || true; \
|
|
done
|
|
|
|
.PHONY: lint
|
|
lint: ## Lint Go code
|
|
@for mod in node geth evm cli; do \
|
|
[ -f "$$mod/go.mod" ] && (cd $$mod && go vet ./...) || true; \
|
|
done
|
|
|
|
##@ Help
|
|
|
|
.PHONY: help
|
|
help: ## Show this help
|
|
@awk 'BEGIN {FS = ":.*##"; printf "$(BOLD)Lux Universe$(RESET) - Triple 5-node networks + services\n\nUsage:\n make $(BLUE)<target>$(RESET) [network=main|test|dev]\n"} \
|
|
/^[a-zA-Z_-]+:.*?##/ { printf " $(BLUE)%-18s$(RESET) %s\n", $$1, $$2 } \
|
|
/^##@/ { printf "\n$(BOLD)%s$(RESET)\n", substr($$0, 5) }' $(MAKEFILE_LIST)
|
|
|
|
local: ## Boot the full stack locally on the hanzo cloud binary (seedable, no external IAM)
|
|
@./local/up.sh
|
|
|
|
##@ IAM — Lux's identity app graph (deterministic, from this repo only)
|
|
|
|
# infra/k8s/iam/provision.yaml is the ONE source of truth for Lux's OAuth
|
|
# clients — never hand-edit an application in a console, or the next converge
|
|
# silently reverts it and the drift is invisible until a login breaks.
|
|
#
|
|
# There are no targets here any more. Converging used to be `make iam-provision`,
|
|
# which built the ConfigMap the Job reads with `kubectl create configmap
|
|
# --from-file` against a context written into this file, so the document the Job
|
|
# actually mounted lived only in whatever cluster somebody last typed at. Both
|
|
# objects are declared in infra/k8s/iam/kustomization.yaml now, so the converge
|
|
# is an apply of a directory and `kubectl diff -k` says whether it is needed.
|
|
#
|
|
# kubectl --context <ctx> diff -k infra/k8s/iam
|
|
# kubectl --context <ctx> apply -k infra/k8s/iam
|
|
# kubectl --context <ctx> -n hanzo logs job/lux-iam-provision --tail=100
|