From 874af2dc962ec9e5999c76f0cc48553bb983abaf Mon Sep 17 00:00:00 2001 From: redpanda-f Date: Fri, 20 Feb 2026 08:33:24 +0000 Subject: [PATCH 1/4] feat: curio logs debug level for pdp --- src/commands/start/curio/daemon.rs | 3 +++ src/commands/start/curio/db_setup.rs | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/src/commands/start/curio/daemon.rs b/src/commands/start/curio/daemon.rs index 1250ba3..d1dc5b2 100644 --- a/src/commands/start/curio/daemon.rs +++ b/src/commands/start/curio/daemon.rs @@ -248,5 +248,8 @@ fn build_docker_create_args( docker_args.extend_from_slice(&["-e".to_string(), env.clone()]); } + docker_args.push("-e".to_string()); + docker_args.push("GOLOG_LOG_LEVEL=pdp=debug".to_string()); + Ok(docker_args) } diff --git a/src/commands/start/curio/db_setup.rs b/src/commands/start/curio/db_setup.rs index b89fc50..068cb79 100644 --- a/src/commands/start/curio/db_setup.rs +++ b/src/commands/start/curio/db_setup.rs @@ -6,6 +6,7 @@ use super::super::step::SetupContext; use super::constants::{DB_SETUP_WAIT_SECS, PDP_LAYER_CONFIG_TEMPLATE}; +use crate::commands::build::docker; use crate::commands::start::foc_deploy::contract_addresses::ContractAddresses; use crate::commands::start::genesis::constants::PDP_SP_MINER_ID_START; use crate::commands::start::lotus_utils::{build_fullnode_api_info, read_lotus_token}; @@ -201,6 +202,9 @@ fn create_base_cluster( docker_args.push(env); } + docker_args.push("-e"); + docker_args.push("GOLOG_LOG_LEVEL=pdp=debug"); + // Add image and command let bash_cmd = format!( "sleep 3 && /usr/local/bin/lotus-bins/curio config new-cluster {}", @@ -311,6 +315,9 @@ fn create_pdp_layer(context: &SetupContext, sp_index: usize) -> Result<(), Box Date: Mon, 23 Feb 2026 07:20:00 +0000 Subject: [PATCH 2/4] fix: remove advertised_address so CQL does not fail on DDL --- src/commands/start/yugabyte/mod.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/commands/start/yugabyte/mod.rs b/src/commands/start/yugabyte/mod.rs index dd46151..baa6b0c 100644 --- a/src/commands/start/yugabyte/mod.rs +++ b/src/commands/start/yugabyte/mod.rs @@ -96,13 +96,19 @@ fn spawn_yugabyte_instance( // Add YugabyteDB startup command with full configuration // CRITICAL: --base_dir must match the volume mount location + // NOTE: Do NOT set --advertise_address=0.0.0.0. gocql (Cassandra driver) queries + // system.local/system.peers after initial connection to discover node addresses. + // If advertise_address is 0.0.0.0, gocql reconnects to 0.0.0.0:9042 which from the + // curio container resolves to curio's own interfaces, causing + // "gocql: no hosts available in the pool" errors even though DDL via the seed succeeds. + // Without --advertise_address, yugabyted auto-detects the container's IP on the Docker + // bridge network, which is reachable by other containers on the same network. docker_args.extend_from_slice(&[ "/yugabyte/bin/yugabyted", "start", "--base_dir=/home/foc-user/yb_base", "--ui=true", "--callhome=false", - "--advertise_address=0.0.0.0", "--master_flags=rpc_bind_addresses=0.0.0.0", "--tserver_flags=rpc_bind_addresses=0.0.0.0,pgsql_proxy_bind_address=0.0.0.0:5433,cql_proxy_bind_address=0.0.0.0:9042", "--daemon=false", From 4b9fed50132e4697e97866c2640254865094430c Mon Sep 17 00:00:00 2001 From: redpanda-f Date: Mon, 23 Feb 2026 07:20:34 +0000 Subject: [PATCH 3/4] feat: workflow testing for pdp-caching-layer being populated --- .../workflows/e2e-test-pdp-caching-layers.yml | 434 ++++++++++++++++++ 1 file changed, 434 insertions(+) create mode 100644 .github/workflows/e2e-test-pdp-caching-layers.yml diff --git a/.github/workflows/e2e-test-pdp-caching-layers.yml b/.github/workflows/e2e-test-pdp-caching-layers.yml new file mode 100644 index 0000000..35c62c1 --- /dev/null +++ b/.github/workflows/e2e-test-pdp-caching-layers.yml @@ -0,0 +1,434 @@ +--- +name: E2E Test - PDP Caching Layers + +on: + workflow_dispatch: + inputs: + curio: + description: > + Curio source location override (e.g., 'gitbranch:main', 'gitcommit:abc123', + 'gittag:v1.0.0'). Leave empty for default. + required: false + default: "" + type: string + lotus: + description: > + Lotus source location override (e.g., 'gitbranch:main', 'gitcommit:abc123', + 'gittag:v1.34.4-rc1'). Leave empty for default. + required: false + default: "" + type: string + filecoin_services: + description: > + Filecoin Services source location override (e.g., 'gitbranch:main', + 'gitcommit:abc123'). Leave empty for default. + required: false + default: "" + type: string + synapse_sdk: + description: > + Synapse SDK source location override (e.g., 'gitbranch:main', + 'gitcommit:abc123', 'gittag:synapse-sdk-v0.36.1'). Leave empty for default. + required: false + default: "" + type: string + +jobs: + e2e-pdp-caching-layers: + runs-on: ["self-hosted", "linux", "x64", "16xlarge+gpu"] + timeout-minutes: 120 + + steps: + # ────────────────────────────────────────────── + # Phase 1: Checkout & Environment Setup + # ────────────────────────────────────────────── + - uses: actions/checkout@v4 + + - name: "EXEC: {Free up disk space}, independent" + uses: endersonmenezes/free-disk-space@v3 + with: + remove_android: true + remove_dotnet: true + remove_haskell: true + remove_tool_cache: true + remove_swap: true + remove_packages: >- + azure-cli google-cloud-cli microsoft-edge-stable google-chrome-stable + firefox postgresql* temurin-* *llvm* mysql* dotnet-sdk-* + remove_packages_one_command: true + remove_folders: >- + /usr/share/swift /usr/share/miniconda /usr/share/az* /usr/local/lib/node_modules + /usr/local/share/chromium /usr/local/share/powershell /usr/local/julia + /usr/local/aws-cli /usr/local/aws-sam-cli /usr/share/gradle + rm_cmd: "rmz" + rmz_version: "3.1.1" + + - name: "EXEC: {Setup Rust toolchain}, independent" + uses: actions-rust-lang/setup-rust-toolchain@v1 + + - name: "EXEC: {Setup Docker}, independent" + uses: docker/setup-buildx-action@v3 + + - name: "EXEC: {Install build dependencies}, independent" + run: | + sudo apt-get update + sudo apt-get install -y tar openssl pkg-config libssl-dev + + # ────────────────────────────────────────────── + # Phase 2: Build foc-devnet binary + # ────────────────────────────────────────────── + - name: "EXEC: {Build foc-devnet binary}, independent" + run: cargo build --release + + - name: "EXEC: {Copy binary and clean Rust artifacts}, independent" + run: | + cp ./target/release/foc-devnet ./foc-devnet + rm -rf ~/.cargo/registry/ + rm -rf ~/.cargo/git/db/ + rm -rf target/ + df -h + + # ────────────────────────────────────────────── + # Phase 3: Initialize, build components, download proof params + # ────────────────────────────────────────────── + - name: "CHECK: {Build init flags from inputs}" + id: init-flags + run: | + FLAGS="" + if [ -n "${{ inputs.curio }}" ]; then + FLAGS="$FLAGS --curio ${{ inputs.curio }}" + fi + if [ -n "${{ inputs.lotus }}" ]; then + FLAGS="$FLAGS --lotus ${{ inputs.lotus }}" + fi + if [ -n "${{ inputs.filecoin_services }}" ]; then + FLAGS="$FLAGS --filecoin-services ${{ inputs.filecoin_services }}" + fi + if [ -n "${{ inputs.synapse_sdk }}" ]; then + FLAGS="$FLAGS --synapse-sdk ${{ inputs.synapse_sdk }}" + fi + echo "flags=$FLAGS" >> $GITHUB_OUTPUT + echo "Init flags: $FLAGS" + + - name: "EXEC: {Initialize foc-devnet}, independent" + run: | + rm -rf ~/.foc-devnet + ./foc-devnet init ${{ steps.init-flags.outputs.flags }} + + - name: "EXEC: {Build Lotus}, independent" + run: ./foc-devnet build lotus + + - name: "EXEC: {Build Curio}, independent" + run: ./foc-devnet build curio + + - name: "EXEC: {Clean up build caches}, independent" + run: | + sudo rm -rf ~/.foc-devnet/docker/volumes/cache + sudo rm -rf ~/.foc-devnet/code/lotus + sudo rm -rf ~/.foc-devnet/code/curio + df -h + + - name: "EXEC: {Download proof parameters from S3}, independent" + run: | + mkdir -p ~/.foc-devnet/docker/volumes/cache/filecoin-proof-parameters/ + curl -L https://fil-proof-params-2k-cache.s3.us-east-2.amazonaws.com/filecoin-proof-params-2k.tar \ + -o /tmp/filecoin-proof-params-2k.tar + tar -xf /tmp/filecoin-proof-params-2k.tar \ + -C ~/.foc-devnet/docker/volumes/cache/filecoin-proof-parameters/ + rm /tmp/filecoin-proof-params-2k.tar + ls -lath ~/.foc-devnet/docker/volumes/cache/filecoin-proof-parameters/ + + # ────────────────────────────────────────────── + # Phase 4: Start devnet + # ────────────────────────────────────────────── + - name: "EXEC: {Configure host.docker.internal}, independent" + run: echo '127.0.0.1 host.docker.internal' | sudo tee -a /etc/hosts + + - name: "EXEC: {Start devnet cluster (notest)}, independent" + id: start_cluster + continue-on-error: true + run: ./foc-devnet start --parallel --notest + + - name: "EXEC: {Collect debug info}, independent" + if: always() + run: | + RUN_DIR="$HOME/.foc-devnet/state/latest" + + echo "+++++++++++ foc-devnet version" + cat "$RUN_DIR/version.txt" 2>/dev/null || echo "No version file found" + + echo "+++++++++++ Disk space" + sudo df -h 2>/dev/null || echo "df command failed" + + echo "+++++++++++ Run Directory Contents" + ls -lath "$RUN_DIR" 2>/dev/null || echo "No run directory found" + + echo "+++++++++++ Contract Addresses" + cat "$RUN_DIR/contract_addresses.json" 2>/dev/null || echo "No contract addresses file found" + + echo "+++++++++++ Step Context" + cat "$RUN_DIR/step_context.json" 2>/dev/null || echo "No step context file found" + + echo "+++++++++++ FOC Metadata" + cat "$RUN_DIR/foc_metadata.json" 2>/dev/null || echo "No foc metadata file found" + + echo "+++++++++++ Container Logs" + if [ -d "$RUN_DIR/logs" ]; then + for logfile in "$RUN_DIR/logs"/*; do + if [ -f "$logfile" ]; then + echo "" + echo "Logs from $(basename "$logfile")" + cat "$logfile" 2>/dev/null || echo "Failed to read $logfile" + fi + done + else + echo "No container logs directory found" + fi + + - name: "EXEC: {Check cluster status}, independent" + run: ./foc-devnet status + + - name: "CHECK: {Fail early if start failed}" + if: steps.start_cluster.outcome == 'failure' + run: | + echo "Devnet start failed. Cannot proceed with e2e tests." >&2 + exit 1 + + # ────────────────────────────────────────────── + # Phase 5: Install test tooling (cqlsh, Node.js) + # ────────────────────────────────────────────── + - name: "EXEC: {Install cqlsh via Python venv}, independent" + run: | + sudo apt-get install -y python3.12-venv + python3 -m venv ~/.foc-devnet/venv + ~/.foc-devnet/venv/bin/pip install cqlsh + + - name: "EXEC: {Setup Node.js}, independent" + uses: actions/setup-node@v4 + with: + node-version: "20" + + # ────────────────────────────────────────────── + # Phase 6: Extract devnet metadata + # ────────────────────────────────────────────── + - name: "CHECK: {Extract devnet info}" + id: devnet-info + run: | + DEVNET_INFO="$HOME/.foc-devnet/state/latest/devnet-info.json" + test -f "$DEVNET_INFO" || { echo "devnet-info.json not found" >&2; exit 1; } + + RUN_ID=$(jq -r '.info.run_id' "$DEVNET_INFO") + echo "run-id=$RUN_ID" >> $GITHUB_OUTPUT + + YUGABYTE_CONTAINER="foc-${RUN_ID}-yugabyte-1" + echo "yugabyte-container=$YUGABYTE_CONTAINER" >> $GITHUB_OUTPUT + + YCQL_PORT=$(docker port "$YUGABYTE_CONTAINER" 9042/tcp | head -1 | cut -d: -f2) + echo "ycql-port=$YCQL_PORT" >> $GITHUB_OUTPUT + + echo "Run ID: $RUN_ID" + echo "Yugabyte container: $YUGABYTE_CONTAINER" + echo "YCQL port: $YCQL_PORT" + + # ────────────────────────────────────────────── + # Phase 7: Assert clean initial state + # ────────────────────────────────────────────── + - name: "CHECK: {Assert initial PDP state is clean}" + env: + YUGABYTE_CONTAINER: ${{ steps.devnet-info.outputs.yugabyte-container }} + YCQL_PORT: ${{ steps.devnet-info.outputs.ycql-port }} + run: | + echo "=== Checking pdp_piecerefs (needs_save_cache should all be false) ===" + PIECEREFS_OUTPUT=$(docker exec -e PGPASSWORD='yugabyte' "$YUGABYTE_CONTAINER" \ + /yugabyte/bin/ysqlsh -h localhost -p 5433 -U yugabyte -d yugabyte -t -A -c \ + "SELECT COUNT(*) FROM curio.pdp_piecerefs WHERE needs_save_cache = true") + NEEDS_SAVE_COUNT=$(echo "$PIECEREFS_OUTPUT" | tr -d '[:space:]') + echo "Pieces with needs_save_cache=true: $NEEDS_SAVE_COUNT" + + if [ "$NEEDS_SAVE_COUNT" != "0" ]; then + echo "FAIL: Expected 0 pieces with needs_save_cache=true, got $NEEDS_SAVE_COUNT" >&2 + docker exec -e PGPASSWORD='yugabyte' "$YUGABYTE_CONTAINER" \ + /yugabyte/bin/ysqlsh -h localhost -p 5433 -U yugabyte -d yugabyte -c \ + "SELECT pr.id, pr.piece_cid, pr.needs_save_cache, pr.caching_task_started, pr.caching_task_completed FROM curio.pdp_piecerefs pr" + exit 1 + fi + + echo "=== Checking pdp_cache_layer (should be empty) ===" + CACHE_LAYER_OUTPUT=$(~/.foc-devnet/venv/bin/cqlsh localhost "$YCQL_PORT" \ + -u cassandra -p cassandra \ + -e "SELECT COUNT(*) FROM curio.pdp_cache_layer;") + echo "Cache layer output: $CACHE_LAYER_OUTPUT" + + CACHE_COUNT=$(echo "$CACHE_LAYER_OUTPUT" | grep -oP '^\s*\K\d+' | head -1) + echo "Cache layer row count: $CACHE_COUNT" + + if [ -n "$CACHE_COUNT" ] && [ "$CACHE_COUNT" != "0" ]; then + echo "FAIL: Expected 0 rows in pdp_cache_layer, got $CACHE_COUNT" >&2 + ~/.foc-devnet/venv/bin/cqlsh localhost "$YCQL_PORT" -u cassandra -p cassandra \ + -e "SELECT * FROM curio.pdp_cache_layer;" + exit 1 + fi + + echo "PASS: Initial PDP state is clean." + + # ────────────────────────────────────────────── + # Phase 8: Run Synapse SDK e2e storage test + # ────────────────────────────────────────────── + - name: "EXEC: {Install Synapse SDK dependencies}, independent" + run: | + SYNAPSE_DIR="$HOME/.foc-devnet/code/synapse-sdk" + if [ ! -d "$SYNAPSE_DIR" ]; then + echo "synapse-sdk directory not found at $SYNAPSE_DIR" >&2 + ls -la "$HOME/.foc-devnet/code/" 2>/dev/null || echo "code dir does not exist" + exit 1 + fi + cd "$SYNAPSE_DIR" + npm install + + - name: "EXEC: {Run Synapse e2e storage runner (10MB + 120MB)}, independent" + id: synapse_e2e + run: | + cd "$HOME/.foc-devnet/code/synapse-sdk" + NETWORK=devnet node utils/example-storage-e2e-runner.js 10MB 120MB + + # ────────────────────────────────────────────── + # Phase 9: Wait for caching tasks and verify + # ────────────────────────────────────────────── + - name: "CHECK: {Wait for PDP SaveCache task to complete}" + env: + RUN_ID: ${{ steps.devnet-info.outputs.run-id }} + YUGABYTE_CONTAINER: ${{ steps.devnet-info.outputs.yugabyte-container }} + run: | + echo "Waiting for PDPv0_SaveCache tasks to complete (max 10 minutes)..." + MAX_WAIT=600 + POLL_INTERVAL=15 + ELAPSED=0 + + while [ $ELAPSED -lt $MAX_WAIT ]; do + PENDING=$(docker exec -e PGPASSWORD='yugabyte' "$YUGABYTE_CONTAINER" \ + /yugabyte/bin/ysqlsh -h localhost -p 5433 -U yugabyte -d yugabyte -t -A -c \ + "SELECT COUNT(*) FROM curio.pdp_piecerefs WHERE needs_save_cache = true AND caching_task_completed IS NULL") + PENDING=$(echo "$PENDING" | tr -d '[:space:]') + + echo "[${ELAPSED}s] Pending caching tasks: $PENDING" + + if [ "$PENDING" = "0" ]; then + echo "All caching tasks completed." + break + fi + + sleep $POLL_INTERVAL + ELAPSED=$((ELAPSED + POLL_INTERVAL)) + done + + if [ $ELAPSED -ge $MAX_WAIT ]; then + echo "TIMEOUT: Caching tasks did not complete within ${MAX_WAIT}s" >&2 + docker exec -e PGPASSWORD='yugabyte' "$YUGABYTE_CONTAINER" \ + /yugabyte/bin/ysqlsh -h localhost -p 5433 -U yugabyte -d yugabyte -c \ + "SELECT pr.id, pr.piece_cid, pr.needs_save_cache, pr.caching_task_started, pr.caching_task_completed FROM curio.pdp_piecerefs pr" + exit 1 + fi + + - name: "CHECK: {Verify SaveCache in curio logs}" + env: + RUN_ID: ${{ steps.devnet-info.outputs.run-id }} + run: | + echo "=== Checking curio container logs for PDPv0_SaveCache ===" + + SAVE_CACHE_HITS=0 + for i in 1 2 3 4 5; do + CONTAINER="foc-${RUN_ID}-curio-${i}" + if docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER}$"; then + echo "--- Logs from $CONTAINER ---" + LOGS=$(docker logs "$CONTAINER" 2>&1 || true) + MATCHES=$(echo "$LOGS" | grep -c "PDPv0_SaveCache: PDP layer cache saved" || true) + echo "SaveCache 'saved' count in $CONTAINER: $MATCHES" + SAVE_CACHE_HITS=$((SAVE_CACHE_HITS + MATCHES)) + echo "$LOGS" | grep "PDPv0_SaveCache" || true + echo "" + fi + done + + echo "Total 'PDP layer cache saved' occurrences: $SAVE_CACHE_HITS" + + if [ "$SAVE_CACHE_HITS" -lt 1 ]; then + echo "FAIL: Expected at least 1 'PDP layer cache saved' log line, got $SAVE_CACHE_HITS" >&2 + exit 1 + fi + + echo "PASS: Found $SAVE_CACHE_HITS SaveCache completion(s) in curio logs." + + - name: "CHECK: {Verify cache layers exist in YCQL}" + env: + YCQL_PORT: ${{ steps.devnet-info.outputs.ycql-port }} + run: | + echo "=== Checking pdp_cache_layer table for cached layers ===" + CACHE_OUTPUT=$(~/.foc-devnet/venv/bin/cqlsh localhost "$YCQL_PORT" \ + -u cassandra -p cassandra \ + -e "SELECT * FROM curio.pdp_cache_layer;") + echo "$CACHE_OUTPUT" + + ROW_COUNT=$(echo "$CACHE_OUTPUT" | grep -oP '\((\d+) rows?\)' | grep -oP '\d+' || echo "0") + echo "Cache layer row count: $ROW_COUNT" + + if [ "$ROW_COUNT" = "0" ] || [ -z "$ROW_COUNT" ]; then + echo "FAIL: Expected rows in pdp_cache_layer after e2e test, found none." >&2 + exit 1 + fi + + echo "PASS: Found $ROW_COUNT rows in pdp_cache_layer." + + - name: "CHECK: {Verify pdp_piecerefs final state}" + env: + YUGABYTE_CONTAINER: ${{ steps.devnet-info.outputs.yugabyte-container }} + run: | + echo "=== Final pdp_piecerefs state ===" + docker exec -e PGPASSWORD='yugabyte' "$YUGABYTE_CONTAINER" \ + /yugabyte/bin/ysqlsh -h localhost -p 5433 -U yugabyte -d yugabyte -c \ + "SELECT pr.id, pr.piece_cid, pr.needs_save_cache, pr.caching_task_started, pr.caching_task_completed FROM curio.pdp_piecerefs pr" + + NEEDS_SAVE=$(docker exec -e PGPASSWORD='yugabyte' "$YUGABYTE_CONTAINER" \ + /yugabyte/bin/ysqlsh -h localhost -p 5433 -U yugabyte -d yugabyte -t -A -c \ + "SELECT COUNT(*) FROM curio.pdp_piecerefs WHERE needs_save_cache = true") + NEEDS_SAVE=$(echo "$NEEDS_SAVE" | tr -d '[:space:]') + + echo "Pieces still needing cache save: $NEEDS_SAVE" + if [ "$NEEDS_SAVE" != "0" ]; then + echo "FAIL: Expected all needs_save_cache to be false after e2e, got $NEEDS_SAVE remaining" >&2 + exit 1 + fi + + echo "PASS: All piecerefs have needs_save_cache=false." + + # ────────────────────────────────────────────── + # Phase 10: On-chain proving verification (placeholder) + # ────────────────────────────────────────────── + - name: "TODO: {Verify on-chain PDP proving}" + run: | + echo "============================================" + echo "PLACEHOLDER: On-chain PDP proving verification" + echo "============================================" + echo "" + echo "This step should verify that PDP proving works on-chain." + echo "Implementation is pending - needs research on how to trigger" + echo "and verify a PDP proving round via the devnet." + echo "" + echo "Expected verification:" + echo " 1. Trigger a PDP proving challenge on-chain" + echo " 2. Wait for the SP to respond with a valid proof" + echo " 3. Verify the proof was accepted by the PDP verifier contract" + echo "" + echo "Skipping for now." + + # ────────────────────────────────────────────── + # Phase 11: Cleanup + # ────────────────────────────────────────────── + - name: "EXEC: {Stop cluster}, independent" + if: always() + run: ./foc-devnet stop + + - name: "CHECK: {Final job status}" + if: always() && steps.start_cluster.outcome == 'failure' + run: | + echo "Devnet start failed; job is marked as failed." >&2 + exit 1 \ No newline at end of file From 011c37f152b30e306b6d0a1ba695db48ad5529e7 Mon Sep 17 00:00:00 2001 From: RedPanda Date: Tue, 24 Feb 2026 13:24:47 +0530 Subject: [PATCH 4/4] Update src/commands/start/curio/db_setup.rs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/commands/start/curio/db_setup.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/commands/start/curio/db_setup.rs b/src/commands/start/curio/db_setup.rs index 068cb79..78a7cbe 100644 --- a/src/commands/start/curio/db_setup.rs +++ b/src/commands/start/curio/db_setup.rs @@ -6,7 +6,6 @@ use super::super::step::SetupContext; use super::constants::{DB_SETUP_WAIT_SECS, PDP_LAYER_CONFIG_TEMPLATE}; -use crate::commands::build::docker; use crate::commands::start::foc_deploy::contract_addresses::ContractAddresses; use crate::commands::start::genesis::constants::PDP_SP_MINER_ID_START; use crate::commands::start::lotus_utils::{build_fullnode_api_info, read_lotus_token};