diff --git a/ADVANCED_README.md b/ADVANCED_README.md index 5d6462d..9191730 100644 --- a/ADVANCED_README.md +++ b/ADVANCED_README.md @@ -97,6 +97,32 @@ foc-devnet stop - Preserves Portainer for persistent access - Clears run ID +### Pausing and Resuming (Resource Saving) + +The devnet cluster can consume significant CPU even when idle. Instead of stopping and restarting, you can pause containers to freeze all processes while preserving state. + +**Pause the cluster (instant, stops all CPU usage):** +```bash +docker ps --filter "name=foc-" -q | xargs docker pause +``` + +**Resume the cluster (instant):** +```bash +docker ps --filter "name=foc-" -q | xargs docker unpause +``` + +**Verify paused state:** +```bash +docker ps --filter "name=foc-" --format "{{.Names}}: {{.Status}}" +# Shows: foc--lotus: Up 12 minutes (Paused) +``` + +**Convenience aliases (add to ~/.bashrc or ~/.zshrc):** +```bash +alias foc-pause='docker ps --filter "name=foc-" -q | xargs docker pause && echo "Cluster paused"' +alias foc-unpause='docker ps --filter "name=foc-" -q | xargs docker unpause && echo "Cluster resumed"' +``` + ### `status` Shows the current status of the foc-devnet system. @@ -1090,9 +1116,6 @@ docker logs foc--curio-2 # Query provider IDs cat ~/.foc-devnet/state/latest/pdp_sps/*.provider_id.json -# Access Yugabyte (shared by all SPs) -docker exec -it foc--yugabyte ysqlsh -h localhost -p 5433 - # Query Lotus for miner info docker exec foc--lotus lotus state miner-info f01000 @@ -1103,6 +1126,16 @@ docker exec foc--builder cast call \ ``` +### Querying Yugabyte Database + +Each Curio has its own Yugabyte (curio-N → yugabyte-N). Tables are in `curio` schema. Credentials: `yugabyte`/`yugabyte`/`yugabyte` (user/pass/db). + +```bash +docker exec foc--yugabyte-1 bash -c "PGPASSWORD=yugabyte /yugabyte/bin/ysqlsh -h 127.0.0.1 -U yugabyte -d yugabyte -c \"\"" +``` + +Key tables: `curio.harmony_machines`, `curio.harmony_task`, `curio.harmony_task_history`, `curio.parked_pieces`. + --- ## Troubleshooting diff --git a/README.md b/README.md index 84bf7f9..2011758 100644 --- a/README.md +++ b/README.md @@ -10,14 +10,27 @@ A developer-friendly tool for spinning up complete Filecoin test networks with s Get up and running in three simple steps: -### Step 0: Ensure non-root user -`foc-devnet` requires itself to be run by a non-root user. Please ensure that you are running as a non-root user which is part of `docker` group. +### Prerequisites -Run the following to see your User ID and groups you are a part of: -``` +**Non-root user with Docker access**: `foc-devnet` must be run by a non-root user in the `docker` group. + +```bash echo $(id -u); groups | grep 'docker' ``` +**Configure host.docker.internal**: Add this entry to `/etc/hosts` so SP URLs work from both host and containers: + +```bash +echo '127.0.0.1 host.docker.internal' | sudo tee -a /etc/hosts +``` + +This is required for SP-to-SP fetch. `foc-devnet start` will check for this and fail with instructions if not configured. + +For GitHub Actions, add this step before running foc-devnet: +```yaml +- run: echo '127.0.0.1 host.docker.internal' | sudo tee -a /etc/hosts +``` + ### Step 1: Initialize ```bash diff --git a/src/commands/start/curio/daemon.rs b/src/commands/start/curio/daemon.rs index 18ef72a..d723271 100644 --- a/src/commands/start/curio/daemon.rs +++ b/src/commands/start/curio/daemon.rs @@ -153,6 +153,8 @@ fn build_docker_create_args( container_name.to_string(), "--network".to_string(), pdp_miner_network_name(run_id, sp_index), + // Enable host.docker.internal for SP-to-SP fetch (resolves to host gateway) + "--add-host=host.docker.internal:host-gateway".to_string(), ]; // Port mappings - get dynamically allocated ports from context diff --git a/src/commands/start/curio/db_setup.rs b/src/commands/start/curio/db_setup.rs index ea6014b..04f14d6 100644 --- a/src/commands/start/curio/db_setup.rs +++ b/src/commands/start/curio/db_setup.rs @@ -68,6 +68,9 @@ pub fn build_foc_contract_env_vars(context: &SetupContext) -> Result .to_string(), ); + // Allow insecure sources (HTTP, localhost, private IPs) for SP-to-SP fetch in devnet + env_vars.push("CURIO_FETCH_ALLOW_INSECURE=1".to_string()); + Ok(env_vars) } diff --git a/src/commands/start/mod.rs b/src/commands/start/mod.rs index 634ca6e..c083682 100644 --- a/src/commands/start/mod.rs +++ b/src/commands/start/mod.rs @@ -36,8 +36,71 @@ use crate::paths::{foc_devnet_config, foc_devnet_run_dir}; use crate::run_id::{create_latest_symlink, save_current_run_id}; use crate::version_info::write_version_file; pub use eth_acc_funding::constants::FEVM_ACCOUNTS_PREFUNDED; +use std::net::ToSocketAddrs; use std::path::{Path, PathBuf}; -use tracing::{info, warn}; +use tracing::{error, info, warn}; + +/// Check that host.docker.internal resolves to 127.0.0.1. +/// +/// This is required for SP-to-SP fetch to work. The hostname must resolve to localhost +/// so that URLs registered in the SP registry work from both the host and inside containers. +/// +/// On macOS with Docker Desktop, this works automatically. +/// On Linux, users must add `127.0.0.1 host.docker.internal` to /etc/hosts. +fn check_host_docker_internal() -> Result<(), Box> { + info!("Checking host.docker.internal resolution..."); + + // Try to resolve host.docker.internal:80 (port doesn't matter, just need DNS resolution) + match "host.docker.internal:80".to_socket_addrs() { + Ok(mut addrs) => { + // Check if any resolved address is 127.0.0.1 + let is_localhost = addrs.any(|addr| addr.ip().is_loopback()); + + if is_localhost { + info!("✓ host.docker.internal resolves to localhost"); + Ok(()) + } else { + error!("════════════════════════════════════════════════════════════════════"); + error!("ERROR: host.docker.internal does not resolve to localhost (127.0.0.1)"); + error!("════════════════════════════════════════════════════════════════════"); + error!(""); + error!("SP-to-SP fetch requires host.docker.internal to resolve to 127.0.0.1"); + error!("so that registered SP URLs work from both host and containers."); + error!(""); + error!("To fix this, add the following line to /etc/hosts:"); + error!(""); + error!(" 127.0.0.1 host.docker.internal"); + error!(""); + error!("You can do this with:"); + error!(" echo '127.0.0.1 host.docker.internal' | sudo tee -a /etc/hosts"); + error!(""); + error!("════════════════════════════════════════════════════════════════════"); + Err("host.docker.internal must resolve to 127.0.0.1".into()) + } + } + Err(_) => { + error!("════════════════════════════════════════════════════════════════════"); + error!("ERROR: host.docker.internal does not resolve"); + error!("════════════════════════════════════════════════════════════════════"); + error!(""); + error!("SP-to-SP fetch requires host.docker.internal to resolve to 127.0.0.1"); + error!("so that registered SP URLs work from both host and containers."); + error!(""); + error!("Add the following line to /etc/hosts:"); + error!(""); + error!(" 127.0.0.1 host.docker.internal"); + error!(""); + error!("You can do this with:"); + error!(" echo '127.0.0.1 host.docker.internal' | sudo tee -a /etc/hosts"); + error!(""); + error!("For GitHub Actions, add this step before running foc-devnet:"); + error!(" - run: echo '127.0.0.1 host.docker.internal' | sudo tee -a /etc/hosts"); + error!(""); + error!("════════════════════════════════════════════════════════════════════"); + Err("host.docker.internal must be resolvable".into()) + } + } +} /// Stop any existing cluster before starting a new one. fn stop_existing_cluster() -> Result<(), Box> { @@ -411,6 +474,9 @@ pub fn start_cluster( run_id: String, notest: bool, ) -> Result<(), Box> { + // Check host.docker.internal resolution first (required for SP-to-SP fetch) + check_host_docker_internal()?; + stop_existing_cluster()?; let (volumes_dir, run_dir, run_id) = diff --git a/src/commands/start/pdp_service_provider/pdp_service_provider_step.rs b/src/commands/start/pdp_service_provider/pdp_service_provider_step.rs index beb8694..16c8f8c 100644 --- a/src/commands/start/pdp_service_provider/pdp_service_provider_step.rs +++ b/src/commands/start/pdp_service_provider/pdp_service_provider_step.rs @@ -201,7 +201,8 @@ impl Step for PdpSpRegistrationStep { let mut provider_ids = Vec::new(); for (sp_index, sp_address, sp_eth_address, pdp_port, should_approve) in sp_data { - let service_url = format!("http://localhost:{}", pdp_port); + // Use host.docker.internal so the URL works from both host and containers + let service_url = format!("http://host.docker.internal:{}", pdp_port); match registration::register_single_provider( ®istration::ProviderRegistrationParams { diff --git a/src/config.rs b/src/config.rs index 34e95cd..8931827 100644 --- a/src/config.rs +++ b/src/config.rs @@ -228,8 +228,8 @@ impl Default for Config { commit: "773551bf1e9cf4cdc49aeb63a47a81f8dc5cb9e1".to_string(), }, yugabyte_download_url: "https://software.yugabyte.com/releases/2.25.1.0/yugabyte-2.25.1.0-b381-linux-x86_64.tar.gz".to_string(), - approved_pdp_sp_count: 1, - active_pdp_sp_count: 1, + approved_pdp_sp_count: 2, + active_pdp_sp_count: 2, } } }