From 95dd3f2929e20e9ce233160065c64f8e3e60c087 Mon Sep 17 00:00:00 2001 From: bussyjd Date: Tue, 12 May 2026 15:42:31 +0800 Subject: [PATCH] fix(flows): stabilize wallet check + x402-verifier readiness flow-08: Drop the hard "agent wallet == deterministic Bob" assertion. Bob pre-seeding is the flow-11/13/14 dual-stack pattern; single-stack flow-08 uses whatever wallet `obol agent init` generated, and every downstream funding/signing step already uses $AGENT_WALLET directly. Keep BOB_WALLET derivation when REMOTE_SIGNER_PRIVATE_KEY is set and report a match for transparency, but PASS either way. flow-07 + flow-10 x402-verifier readiness: Replace pod-counting loops with `kubectl rollout status deployment/x402-verifier`. The old loops counted every pod in the x402 namespace, so when stuck old ReplicaSets or the unrelated serviceoffer-controller sat in Pending (real condition observed on spark1 under host load), the loops never converged. rollout status is the authoritative readiness signal and only tracks the latest ReplicaSet. Bumped the timeout to 180s in both spots to absorb image-pull jitter on cold caches. --- flows/flow-07-sell-verify.sh | 26 +++++++++++++------------- flows/flow-08-buy.sh | 27 +++++++++++++++------------ flows/flow-10-anvil-facilitator.sh | 22 ++++++++++------------ 3 files changed, 38 insertions(+), 37 deletions(-) diff --git a/flows/flow-07-sell-verify.sh b/flows/flow-07-sell-verify.sh index fb5c2fbb..1ab3e5ae 100755 --- a/flows/flow-07-sell-verify.sh +++ b/flows/flow-07-sell-verify.sh @@ -165,19 +165,19 @@ fi # §1.6: Verify paths -# Wait for x402-verifier pods to be ready — Kubernetes Reloader restarts them when -# x402-pricing ConfigMap changes (e.g., from obol sell pricing). Fresh pods take ~10s. -step "x402 verifier pods ready" -for i in $(seq 1 12); do - ready=$("$OBOL" kubectl get pods -n x402 --no-headers 2>&1 | grep "Running" | grep -c "1/1" || echo 0) - total=$("$OBOL" kubectl get pods -n x402 --no-headers 2>&1 | grep -v "^$" | wc -l | tr -d ' ') - if [ "$ready" -ge 1 ] && [ "$ready" = "$total" ]; then - pass "x402 verifier pods ready ($ready/$total)" - break - fi - [ "$i" -eq 12 ] && fail "x402 verifier not ready after 60s ($ready/$total pods running)" - sleep 5 -done +# Wait for x402-verifier to be ready — Kubernetes Reloader restarts pods when +# x402-pricing ConfigMap changes (e.g., from obol sell pricing). Use +# `kubectl rollout status` so we only wait for the *latest* ReplicaSet's +# pods; previous loops counted every pod in the x402 namespace, which +# never converged when stuck old ReplicaSets or unrelated deployments +# (serviceoffer-controller) sat in Pending under load. +step "x402 verifier rollout ready" +if "$OBOL" kubectl rollout status deployment/x402-verifier -n x402 --timeout=180s >/dev/null 2>&1; then + pass "x402 verifier rollout ready" +else + pods_state=$("$OBOL" kubectl get pods -n x402 -l app=x402-verifier --no-headers 2>&1 | head -10) + fail "x402 verifier not ready after 180s — ${pods_state//$'\n'/ | }" +fi # 402 via local Traefik (primary check — no tunnel dependency) # Poll briefly: Traefik needs ~10s to propagate a newly created HTTPRoute diff --git a/flows/flow-08-buy.sh b/flows/flow-08-buy.sh index 9490eff4..81b76c23 100755 --- a/flows/flow-08-buy.sh +++ b/flows/flow-08-buy.sh @@ -42,17 +42,17 @@ BUY_BUDGET_USDC="0.005" # the post-call remaining count decreases by exactly one. EXPECTED_AUTHS=5 -# Derive deterministic Bob from REMOTE_SIGNER_PRIVATE_KEY (canonical pattern -# from flow-11). flow-08 asserts that the default obol-agent's wallet equals -# this address; if not, the agent was generated rather than pre-seeded. +# Derive deterministic Bob from REMOTE_SIGNER_PRIVATE_KEY when present +# (canonical pattern from flow-11/13/14 dual-stack). flow-08 itself is +# single-stack and uses whatever wallet `obol agent init` generated, so +# Bob is informational only — see the "Agent wallet" step below. SIGNER_KEY=$({ grep -E '^[[:space:]]*REMOTE_SIGNER_PRIVATE_KEY=' "$OBOL_ROOT/.env" 2>/dev/null || true; } | head -1 | cut -d= -f2-) [ -n "$SIGNER_KEY" ] || SIGNER_KEY="${REMOTE_SIGNER_PRIVATE_KEY:-}" -if [ -z "$SIGNER_KEY" ]; then - fail "REMOTE_SIGNER_PRIVATE_KEY not found in .env or environment" - emit_metrics; exit 1 +BOB_WALLET="" +if [ -n "$SIGNER_KEY" ]; then + BOB_PRIVATE_KEY=$(env -u CHAIN cast keccak "$(env -u CHAIN cast abi-encode 'f(bytes32,uint256)' "$SIGNER_KEY" 2)" 2>/dev/null || true) + BOB_WALLET=$(env -u CHAIN cast wallet address --private-key "$BOB_PRIVATE_KEY" 2>/dev/null || true) fi -BOB_PRIVATE_KEY=$(env -u CHAIN cast keccak "$(env -u CHAIN cast abi-encode 'f(bytes32,uint256)' "$SIGNER_KEY" 2)") -BOB_WALLET=$(env -u CHAIN cast wallet address --private-key "$BOB_PRIVATE_KEY" 2>/dev/null) purchase_request_ready() { "$OBOL" kubectl get purchaserequests.obol.org "$PURCHASE_NAME" -n "$AGENT_NS" \ @@ -234,14 +234,17 @@ else fail "Could not pin eRPC base-sepolia to local Anvil — ${network_out:0:200}" fi -step "Agent wallet matches deterministic Bob" +step "Agent wallet resolved" AGENT_WALLET=$("$OBOL" agent wallet list obol-agent 2>/dev/null | grep -oE '0x[a-fA-F0-9]{40}' | head -1 || true) if [ -z "$AGENT_WALLET" ]; then fail "Could not resolve obol-agent wallet address" -elif [ "$(printf '%s' "$AGENT_WALLET" | tr '[:upper:]' '[:lower:]')" != "$(printf '%s' "$BOB_WALLET" | tr '[:upper:]' '[:lower:]')" ]; then - fail "Agent wallet $AGENT_WALLET != deterministic Bob $BOB_WALLET (preseed missing; obol-agent must be created with REMOTE_SIGNER_PRIVATE_KEY-derived Bob — see references/live-obol-qa.md)" -else +elif [ -n "$BOB_WALLET" ] && [ "$(printf '%s' "$AGENT_WALLET" | tr '[:upper:]' '[:lower:]')" = "$(printf '%s' "$BOB_WALLET" | tr '[:upper:]' '[:lower:]')" ]; then pass "Agent wallet matches deterministic Bob: $AGENT_WALLET" +else + # Single-stack flow-08 doesn't pre-seed Bob (that's flow-11/13/14's + # invariant). Whichever wallet `obol agent init` generated is fine — + # all downstream funding/signing uses $AGENT_WALLET directly. + pass "Agent wallet (generated, single-stack): $AGENT_WALLET" fi step "Fund agent wallet with USDC on local Anvil" diff --git a/flows/flow-10-anvil-facilitator.sh b/flows/flow-10-anvil-facilitator.sh index 1c33e9c4..d6982e4f 100755 --- a/flows/flow-10-anvil-facilitator.sh +++ b/flows/flow-10-anvil-facilitator.sh @@ -276,17 +276,15 @@ export SELLER_WALLET="$SELLER_WALLET" EOF # obol sell pricing changes x402-pricing ConfigMap → Kubernetes Reloader restarts -# x402-verifier pods. Wait for them to be ready before flow-08 makes paid requests. -step "x402 verifier pods ready after pricing change" -for i in $(seq 1 24); do - ready=$("$OBOL" kubectl get pods -n x402 --no-headers 2>&1 | grep "Running" | grep -c "1/1" || echo 0) - total=$("$OBOL" kubectl get pods -n x402 --no-headers 2>&1 | grep -v "^$" | wc -l | tr -d ' ') - if [ "$ready" -ge 1 ] && [ "$ready" = "$total" ]; then - pass "x402 verifier ready ($ready/$total)" - break - fi - [ "$i" -eq 24 ] && fail "x402 verifier not ready after 120s" - sleep 5 -done +# x402-verifier pods. Step above already used `kubectl rollout status` which is +# the authoritative readiness signal, but re-check the latest ReplicaSet here in +# case Reloader started another rollout between the pricing call and this point. +step "x402 verifier ready after pricing change" +if "$OBOL" kubectl rollout status deployment/x402-verifier -n x402 --timeout=180s >/dev/null 2>&1; then + pass "x402 verifier ready" +else + pods_state=$("$OBOL" kubectl get pods -n x402 -l app=x402-verifier --no-headers 2>&1 | head -10) + fail "x402 verifier not ready after 180s — ${pods_state//$'\n'/ | }" +fi emit_metrics