From 28becfbc940bba040650ccf7cb3f13a65b2f9188 Mon Sep 17 00:00:00 2001 From: Gabriele Picco Date: Fri, 24 Apr 2026 17:35:40 -0400 Subject: [PATCH 1/9] fix: ci/cd tests --- .github/workflows/test-examples.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-examples.yml b/.github/workflows/test-examples.yml index a16a931..e54327e 100644 --- a/.github/workflows/test-examples.yml +++ b/.github/workflows/test-examples.yml @@ -67,7 +67,7 @@ jobs: RUST_LOG=info ephemeral-validator \ --remotes "http://localhost:8899" \ --remotes "ws://localhost:8900" \ - -l "7799" \ + -l "127.0.0.1:7799" \ --lifecycle ephemeral \ > /tmp/ephemeral-validator.log 2>&1 & From b91cf144f8bb17714298a274aa9e87c76bcbfce0 Mon Sep 17 00:00:00 2001 From: Gabriele Picco Date: Fri, 24 Apr 2026 18:15:35 -0400 Subject: [PATCH 2/9] fix: ci/cd tests --- .github/workflows/test-examples.yml | 39 +---------------------------- fullstack-test.sh | 25 ++++++++++++++++-- 2 files changed, 24 insertions(+), 40 deletions(-) diff --git a/.github/workflows/test-examples.yml b/.github/workflows/test-examples.yml index e54327e..1a91cc2 100644 --- a/.github/workflows/test-examples.yml +++ b/.github/workflows/test-examples.yml @@ -49,48 +49,11 @@ jobs: solana config set --url localhost solana-keygen new --no-bip39-passphrase --silent --outfile ~/.config/solana/id.json - - name: Start Solana Test Validator - run: | - mb-test-validator \ - --ledger ./my-ledger-1 \ - --reset & - - # Wait for validator to be ready - timeout 30 bash -c 'until solana cluster-version --url http://localhost:8899 >/dev/null 2>&1; do sleep 1; done' - - - name: Start MagicBlock Ephemeral Validator - run: | - # Magic voodoo to increase resource limits - sudo prlimit --pid $$ --nofile=1048576:1048576 - sudo sysctl fs.inotify.max_user_instances=1280 - sudo sysctl fs.inotify.max_user_watches=655360 - RUST_LOG=info ephemeral-validator \ - --remotes "http://localhost:8899" \ - --remotes "ws://localhost:8900" \ - -l "127.0.0.1:7799" \ - --lifecycle ephemeral \ - > /tmp/ephemeral-validator.log 2>&1 & - - # Wait for validator to be ready - timeout 60 bash -c 'until curl -s http://localhost:7799 >/dev/null 2>&1; do sleep 1; done' || { - echo "ephemeral-validator did not become ready within 60 seconds" - echo "=== Last 100 lines of validator log ===" - tail -100 /tmp/ephemeral-validator.log || true - exit 1 - } - name: Test anchor-counter run: | cd anchor-counter - anchor build && anchor deploy --provider.cluster localnet yarn install - EPHEMERAL_PROVIDER_ENDPOINT="http://localhost:7799" \ - EPHEMERAL_WS_ENDPOINT="ws://localhost:7800" \ - PROVIDER_ENDPOINT=http://localhost:8899 \ - WS_ENDPOINT=http://localhost:8900 \ - anchor test \ - --provider.cluster localnet \ - --skip-local-validator \ - --skip-deploy + anchor test # - name: Test anchor-minter # run: | diff --git a/fullstack-test.sh b/fullstack-test.sh index ebaef66..0d89f48 100755 --- a/fullstack-test.sh +++ b/fullstack-test.sh @@ -111,10 +111,16 @@ if [ -z "$CLUSTER" ]; then exit 1 fi +# Restore the terminal before printing anything in case a previous validator run +# left newline translation disabled. +[ -t 1 ] && stty sane < /dev/tty 2>/dev/null || true + echo -e "${GREEN}Detected Cluster: ${CLUSTER}${NC}" # Cleanup function cleanup() { + # Belt-and-braces: restore the TTY if a validator's progress UI left it in raw mode. + [ -t 1 ] && stty sane < /dev/tty 2>/dev/null || true if [ "$CLUSTER" = "localnet" ]; then # Only cleanup validators if we started them if [ "$MB_VALIDATOR_STARTED_BY_US" = true ] || [ "$EPHEMERAL_VALIDATOR_STARTED_BY_US" = true ]; then @@ -203,6 +209,7 @@ if [ "$CLUSTER" = "localnet" ]; then for i in {1..60}; do if curl -s http://127.0.0.1:8899/health > /dev/null 2>&1; then echo -e "${GREEN}solana-test-validator is ready${NC}" + [ -t 1 ] && stty sane < /dev/tty 2>/dev/null || true break fi if [ $i -eq 60 ]; then @@ -235,13 +242,27 @@ if [ "$CLUSTER" = "localnet" ]; then # Wait for ephemeral-validator to be ready echo -e "${YELLOW}Waiting for ephemeral-validator to be ready...${NC}" for i in {1..60}; do - if curl -s http://127.0.0.1:7799/health > /dev/null 2>&1; then + if curl -s --max-time 1 http://127.0.0.1:7799/health > /dev/null 2>&1; then echo -e "${GREEN}ephemeral-validator is ready${NC}" + [ -t 1 ] && stty sane < /dev/tty 2>/dev/null || true break fi + if ! kill -0 "$EPHEMERAL_VALIDATOR_PID" 2>/dev/null; then + echo -e "${RED}Error: ephemeral-validator exited before becoming ready${NC}" + if [ -f /tmp/ephemeral-validator.log ]; then + echo "Startup log (/tmp/ephemeral-validator.log):" + sed -n '1,80p' /tmp/ephemeral-validator.log + fi + exit 1 + fi if [ $i -eq 60 ]; then echo -e "${RED}Error: ephemeral-validator failed to start${NC}" - echo "Check logs at /tmp/ephemeral-validator.log" + if [ -f /tmp/ephemeral-validator.log ]; then + echo "Startup log (/tmp/ephemeral-validator.log):" + sed -n '1,80p' /tmp/ephemeral-validator.log + else + echo "Check logs at /tmp/ephemeral-validator.log" + fi exit 1 fi sleep 1 From f924bbc331ebc5eb20f591733687a6bce2873aa7 Mon Sep 17 00:00:00 2001 From: Gabriele Picco Date: Fri, 24 Apr 2026 18:24:33 -0400 Subject: [PATCH 3/9] fix: ci/cd tests --- .github/workflows/test-examples.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/test-examples.yml b/.github/workflows/test-examples.yml index 1a91cc2..e2b9188 100644 --- a/.github/workflows/test-examples.yml +++ b/.github/workflows/test-examples.yml @@ -49,6 +49,12 @@ jobs: solana config set --url localhost solana-keygen new --no-bip39-passphrase --silent --outfile ~/.config/solana/id.json + - name: Configure Validator Limits + run: | + sudo prlimit --pid $$ --nofile=1048576:1048576 + sudo sysctl fs.inotify.max_user_instances=1280 + sudo sysctl fs.inotify.max_user_watches=655360 + - name: Test anchor-counter run: | cd anchor-counter From 53d3634d7deae837405f57c1a40703ae9d34b304 Mon Sep 17 00:00:00 2001 From: Gabriele Picco Date: Fri, 24 Apr 2026 18:43:13 -0400 Subject: [PATCH 4/9] fix: ci/cd tests --- .github/workflows/test-examples.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-examples.yml b/.github/workflows/test-examples.yml index e2b9188..87dfb58 100644 --- a/.github/workflows/test-examples.yml +++ b/.github/workflows/test-examples.yml @@ -51,12 +51,12 @@ jobs: - name: Configure Validator Limits run: | - sudo prlimit --pid $$ --nofile=1048576:1048576 sudo sysctl fs.inotify.max_user_instances=1280 sudo sysctl fs.inotify.max_user_watches=655360 - name: Test anchor-counter run: | + sudo prlimit --pid $$ --nofile=1048576:1048576 cd anchor-counter yarn install anchor test From d919d2a57c3a93e562477171a92f5875b1df477b Mon Sep 17 00:00:00 2001 From: Gabriele Picco Date: Sat, 25 Apr 2026 11:47:07 -0400 Subject: [PATCH 5/9] fix: ci/cd tests --- fullstack-test.sh | 79 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 57 insertions(+), 22 deletions(-) diff --git a/fullstack-test.sh b/fullstack-test.sh index 0d89f48..043d36a 100755 --- a/fullstack-test.sh +++ b/fullstack-test.sh @@ -58,6 +58,17 @@ has_anchor_cli_skip_local_validator() { return 1 } +dump_validator_logs() { + if [ -f /tmp/ephemeral-validator.log ]; then + echo "=== ephemeral-validator log (size=$(wc -c < /tmp/ephemeral-validator.log) bytes) ===" + sed -n '1,200p' /tmp/ephemeral-validator.log + fi + if [ -f /tmp/mb-test-validator.log ]; then + echo "=== mb-test-validator log (size=$(wc -c < /tmp/mb-test-validator.log) bytes) ===" + sed -n '1,200p' /tmp/mb-test-validator.log + fi +} + airdrop_upgrade_authority() { local cluster_url=$1 local keypair=${2:-"${HOME}/.config/solana/id.json"} @@ -168,8 +179,22 @@ if [ "$CLUSTER" = "localnet" ]; then if check_port 8899 && ! pgrep -f "mb-test-validator" > /dev/null 2>&1; then echo -e "${YELLOW}Non-MagicBlock validator detected on port 8899, killing it...${NC}" echo -e "${YELLOW}Tip: run with 'anchor test --skip-local-validator --skip-build --skip-deploy' to avoid this${NC}" - lsof -ti :8899 | xargs kill 2>/dev/null - sleep 1 + lsof -ti :8899 | xargs -r kill -TERM 2>/dev/null || true + for _ in $(seq 1 10); do + check_port 8899 || break + sleep 0.5 + done + if check_port 8899; then + lsof -ti :8899 | xargs -r kill -KILL 2>/dev/null || true + for _ in $(seq 1 10); do + check_port 8899 || break + sleep 0.5 + done + fi + if check_port 8899; then + echo -e "${RED}Error: port 8899 is still in use after kill${NC}" + exit 1 + fi fi fi @@ -204,17 +229,33 @@ if [ "$CLUSTER" = "localnet" ]; then MB_VALIDATOR_PID=$! MB_VALIDATOR_STARTED_BY_US=true - # Wait for solana-test-validator to be ready - echo -e "${YELLOW}Waiting for solana-test-validator to be ready...${NC}" - for i in {1..60}; do - if curl -s http://127.0.0.1:8899/health > /dev/null 2>&1; then - echo -e "${GREEN}solana-test-validator is ready${NC}" + # Wait for solana-test-validator to be producing slots. /health returns "ok" + # well before the bank is producing — ephemeral-validator's chainlink fails to + # bootstrap against a non-producing remote and exits silently. + echo -e "${YELLOW}Waiting for solana-test-validator to be producing slots...${NC}" + for i in $(seq 1 90); do + if [ "$MB_VALIDATOR_STARTED_BY_US" = true ] && ! kill -0 "$MB_VALIDATOR_PID" 2>/dev/null; then + echo -e "${RED}Error: mb-test-validator exited before becoming ready${NC}" + if [ -f /tmp/mb-test-validator.log ]; then + echo "Startup log (/tmp/mb-test-validator.log):" + sed -n '1,200p' /tmp/mb-test-validator.log + fi + exit 1 + fi + slot=$(curl -s --max-time 1 -X POST -H "content-type: application/json" \ + -d '{"jsonrpc":"2.0","method":"getSlot","id":1}' http://127.0.0.1:8899 2>/dev/null \ + | sed -n 's/.*"result":\([0-9]\+\).*/\1/p') + if [ -n "$slot" ] && [ "$slot" -gt 0 ]; then + echo -e "${GREEN}solana-test-validator is ready (slot=$slot)${NC}" [ -t 1 ] && stty sane < /dev/tty 2>/dev/null || true break fi - if [ $i -eq 60 ]; then - echo -e "${RED}Error: solana-test-validator failed to start${NC}" - echo "Check logs at /tmp/mb-test-validator.log" + if [ $i -eq 90 ]; then + echo -e "${RED}Error: solana-test-validator failed to produce slots within 90s${NC}" + if [ -f /tmp/mb-test-validator.log ]; then + echo "Startup log (/tmp/mb-test-validator.log):" + sed -n '1,200p' /tmp/mb-test-validator.log + fi exit 1 fi sleep 1 @@ -248,21 +289,15 @@ if [ "$CLUSTER" = "localnet" ]; then break fi if ! kill -0 "$EPHEMERAL_VALIDATOR_PID" 2>/dev/null; then - echo -e "${RED}Error: ephemeral-validator exited before becoming ready${NC}" - if [ -f /tmp/ephemeral-validator.log ]; then - echo "Startup log (/tmp/ephemeral-validator.log):" - sed -n '1,80p' /tmp/ephemeral-validator.log - fi + wait "$EPHEMERAL_VALIDATOR_PID" 2>/dev/null + ev_exit=$? + echo -e "${RED}Error: ephemeral-validator exited before becoming ready (exit=${ev_exit})${NC}" + dump_validator_logs exit 1 fi if [ $i -eq 60 ]; then - echo -e "${RED}Error: ephemeral-validator failed to start${NC}" - if [ -f /tmp/ephemeral-validator.log ]; then - echo "Startup log (/tmp/ephemeral-validator.log):" - sed -n '1,80p' /tmp/ephemeral-validator.log - else - echo "Check logs at /tmp/ephemeral-validator.log" - fi + echo -e "${RED}Error: ephemeral-validator failed to start within 60s${NC}" + dump_validator_logs exit 1 fi sleep 1 From d3e5910b71bba55ff5c331ace961bb63342dc4a3 Mon Sep 17 00:00:00 2001 From: Gabriele Picco Date: Sat, 25 Apr 2026 12:28:24 -0400 Subject: [PATCH 6/9] fix: ci/cd tests --- .github/workflows/test-examples.yml | 2 +- fullstack-test.sh | 49 +++++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-examples.yml b/.github/workflows/test-examples.yml index 87dfb58..20cec97 100644 --- a/.github/workflows/test-examples.yml +++ b/.github/workflows/test-examples.yml @@ -59,7 +59,7 @@ jobs: sudo prlimit --pid $$ --nofile=1048576:1048576 cd anchor-counter yarn install - anchor test + anchor test --provider.cluster localnet # - name: Test anchor-minter # run: | diff --git a/fullstack-test.sh b/fullstack-test.sh index 043d36a..dc58726 100755 --- a/fullstack-test.sh +++ b/fullstack-test.sh @@ -51,6 +51,46 @@ has_ancestor_flag() { return 1 } +get_provider_cluster_override() { + # Inspect this script's own args first. + local prev="" + for arg in "$@"; do + case "$arg" in + --provider.cluster=*) + echo "${arg#--provider.cluster=}" + return 0 + ;; + esac + if [ "$prev" = "--provider.cluster" ]; then + echo "$arg" + return 0 + fi + prev="$arg" + done + + # Then walk ancestor processes — anchor's own argv is what we usually find. + local pid=$$ + local depth=0 + local cmd + local match + while [ -n "$pid" ] && [ "$pid" -ne 1 ] && [ "$depth" -lt 20 ]; do + cmd="$(ps -p "$pid" -o args= -ww 2>/dev/null | tr '\n' ' ')" + match="$(echo "$cmd" | sed -nE 's/.*--provider\.cluster[ =]+([^ ]+).*/\1/p' | head -1)" + if [ -n "$match" ]; then + echo "$match" + return 0 + fi + local ppid + ppid="$(ps -p "$pid" -o ppid= 2>/dev/null | tr -d ' ')" + if [ -z "$ppid" ] || [ "$ppid" = "$pid" ] || [ "$ppid" = "0" ]; then + break + fi + pid="$ppid" + depth=$((depth + 1)) + done + return 1 +} + has_anchor_cli_skip_local_validator() { if pgrep -af "anchor" 2>/dev/null | awk '($0 ~ /test/) && ($0 ~ /--skip-local-validator/) { found=1; exit } END { exit (found?0:1) }'; then return 0 @@ -116,9 +156,14 @@ if [ ! -f "$ANCHOR_TOML" ]; then exit 1 fi -CLUSTER=$(grep -A 1 "^\[provider\]" "$ANCHOR_TOML" | grep "cluster" | sed 's/.*cluster = "\(.*\)".*/\1/' | tr -d ' ') +# --provider.cluster on the anchor CLI wins over Anchor.toml so that callers +# (CI, local overrides) can target a different cluster without rewriting the file. +CLUSTER="$(get_provider_cluster_override "$@" || true)" +if [ -z "$CLUSTER" ]; then + CLUSTER=$(grep -A 1 "^\[provider\]" "$ANCHOR_TOML" | grep "cluster" | sed 's/.*cluster = "\(.*\)".*/\1/' | tr -d ' ') +fi if [ -z "$CLUSTER" ]; then - echo -e "${RED}Error: Could not determine cluster from Anchor.toml${NC}" + echo -e "${RED}Error: Could not determine cluster (no --provider.cluster flag and no [provider] cluster in Anchor.toml)${NC}" exit 1 fi From 4fb692e6d4963a26a249b02a4256ce08ea55af21 Mon Sep 17 00:00:00 2001 From: Gabriele Picco Date: Sat, 25 Apr 2026 15:32:34 -0400 Subject: [PATCH 7/9] fix: ci/cd tests - Wrap ephemeral-validator in a pty (python3) so its mandatory ratatui/crossterm TUI sees a controlling terminal; without one it silently exits 0 before binding port 7799, both in CI and when invoked from a non-tty bg job. - Move test endpoint env vars (PROVIDER_ENDPOINT, EPHEMERAL_PROVIDER_ENDPOINT, TEE_PROVIDER_ENDPOINT, ROUTER_ENDPOINT, WS variants) to the workflow step so the test runner doesn't fall back to devnet defaults. Tests read these directly; setting them inside fullstack-test.sh leaked project conventions into the script. - Set anchor-counter Anchor.toml cluster to "localnet" so the merge of main into this branch keeps localnet (was reverting to "devnet" via 3-way merge). - Commit private-/public-counter program keypairs and update .gitignore so deploy doesn't fail with DeclaredProgramIdMismatch on fresh clones; declare_id!() values now match the committed keypairs (no anchor keys sync needed). - fullstack-test.sh: wait for the upstream validator to be producing slots (commitment=processed) before starting ephemeral-validator; portable sed -E for slot extraction (BSD vs GNU); harden the kill of anchor's pre-flight validator with SIGTERM->SIGKILL and a port-free poll; honor --provider.cluster override from the anchor CLI; print mb-test-validator log on ephemeral failure with ANSI codes stripped. - Workflow: set kernel inotify limits ahead of time, raise nofile via prlimit in the same step as anchor test (prlimit on $$ doesn't propagate across GitHub Actions step shells). --- .github/workflows/test-examples.yml | 7 ++++ .gitignore | 4 +- anchor-counter/.gitignore | 4 +- anchor-counter/Anchor.toml | 2 +- .../programs/private-counter/src/lib.rs | 2 +- .../programs/public-counter/src/lib.rs | 2 +- .../deploy/private_counter-keypair.json | 1 + .../target/deploy/public_counter-keypair.json | 1 + anchor-counter/yarn.lock | 41 ++++--------------- fullstack-test.sh | 37 ++++++++++++----- 10 files changed, 54 insertions(+), 47 deletions(-) create mode 100644 anchor-counter/target/deploy/private_counter-keypair.json create mode 100644 anchor-counter/target/deploy/public_counter-keypair.json diff --git a/.github/workflows/test-examples.yml b/.github/workflows/test-examples.yml index 20cec97..11356a1 100644 --- a/.github/workflows/test-examples.yml +++ b/.github/workflows/test-examples.yml @@ -55,6 +55,13 @@ jobs: sudo sysctl fs.inotify.max_user_watches=655360 - name: Test anchor-counter + env: + PROVIDER_ENDPOINT: http://127.0.0.1:8899 + WS_ENDPOINT: ws://127.0.0.1:8900 + EPHEMERAL_PROVIDER_ENDPOINT: http://127.0.0.1:7799 + EPHEMERAL_WS_ENDPOINT: ws://127.0.0.1:7800 + TEE_PROVIDER_ENDPOINT: http://127.0.0.1:7799 + ROUTER_ENDPOINT: http://127.0.0.1:7799 run: | sudo prlimit --pid $$ --nofile=1048576:1048576 cd anchor-counter diff --git a/.gitignore b/.gitignore index 472cec5..69aa647 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,9 @@ **/.next/ **/.env **/tsconfig.tsbuildinfo -!/anchor-counter/target/deploy/anchor_counter-keypair.json +!/anchor-counter/target/deploy/ +/anchor-counter/target/deploy/* +!/anchor-counter/target/deploy/*-keypair.json !/bolt-counter/target/deploy/counter-keypair.json !/bolt-counter/target/deploy/increase-keypair.json diff --git a/anchor-counter/.gitignore b/anchor-counter/.gitignore index 33fe907..3cf3032 100644 --- a/anchor-counter/.gitignore +++ b/anchor-counter/.gitignore @@ -10,7 +10,9 @@ **/.next/ **/.env **/magicblock-test-storage -!/anchor-counter/target/deploy/anchor_counter-keypair.json +!target/deploy/ +target/deploy/* +!target/deploy/*-keypair.json !/bolt-counter/target/deploy/counter-keypair.json !/bolt-counter/target/deploy/increase-keypair.json diff --git a/anchor-counter/Anchor.toml b/anchor-counter/Anchor.toml index aaa99bd..747175b 100644 --- a/anchor-counter/Anchor.toml +++ b/anchor-counter/Anchor.toml @@ -9,7 +9,7 @@ skip-lint = false url = "https://api.apr.dev" [provider] -cluster = "devnet" +cluster = "localnet" wallet = "~/.config/solana/id.json" [scripts] diff --git a/anchor-counter/programs/private-counter/src/lib.rs b/anchor-counter/programs/private-counter/src/lib.rs index 0ef4e45..4325a1d 100644 --- a/anchor-counter/programs/private-counter/src/lib.rs +++ b/anchor-counter/programs/private-counter/src/lib.rs @@ -9,7 +9,7 @@ use ephemeral_rollups_sdk::consts::PERMISSION_PROGRAM_ID; use ephemeral_rollups_sdk::cpi::DelegateConfig; use ephemeral_rollups_sdk::ephem::MagicIntentBundleBuilder; -declare_id!("91L33vBqfNaNfieqNCoqpxGZ2xVyJ29N3VcErR6LoepZ"); +declare_id!("7Y2rYVGqRY31m7ogMHjmtdRMUjeWakoJ6iVx12i6voCY"); pub const COUNTER_SEED: &[u8] = b"counter"; diff --git a/anchor-counter/programs/public-counter/src/lib.rs b/anchor-counter/programs/public-counter/src/lib.rs index b7f48e4..699b426 100644 --- a/anchor-counter/programs/public-counter/src/lib.rs +++ b/anchor-counter/programs/public-counter/src/lib.rs @@ -3,7 +3,7 @@ use ephemeral_rollups_sdk::anchor::{commit, delegate, ephemeral}; use ephemeral_rollups_sdk::cpi::DelegateConfig; use ephemeral_rollups_sdk::ephem::MagicIntentBundleBuilder; -declare_id!("9RPwaXayVZHna1BYuRS4cLPJZuNGU1uS5V3heXB7v6Qi"); +declare_id!("A4D1N6zdiwtAFr7mQcHkNbk2yXmDcpvovvU5D27kZoGv"); pub const COUNTER_SEED: &[u8] = b"counter"; diff --git a/anchor-counter/target/deploy/private_counter-keypair.json b/anchor-counter/target/deploy/private_counter-keypair.json new file mode 100644 index 0000000..397428b --- /dev/null +++ b/anchor-counter/target/deploy/private_counter-keypair.json @@ -0,0 +1 @@ +[119,46,244,54,52,50,191,114,206,197,170,24,175,166,19,3,6,17,59,122,49,186,70,124,216,43,13,202,198,181,103,214,97,25,57,34,18,212,173,207,238,164,136,58,10,45,107,233,195,189,65,84,182,242,104,176,149,52,246,45,128,129,82,141] \ No newline at end of file diff --git a/anchor-counter/target/deploy/public_counter-keypair.json b/anchor-counter/target/deploy/public_counter-keypair.json new file mode 100644 index 0000000..d3e09b8 --- /dev/null +++ b/anchor-counter/target/deploy/public_counter-keypair.json @@ -0,0 +1 @@ +[106,108,44,14,228,142,138,192,251,141,149,227,72,172,124,173,42,3,203,113,154,21,153,82,212,199,168,15,115,100,198,39,134,139,128,19,183,247,83,39,234,34,183,10,57,232,90,108,188,49,31,188,22,201,57,242,183,210,9,200,162,251,250,195] \ No newline at end of file diff --git a/anchor-counter/yarn.lock b/anchor-counter/yarn.lock index a1def62..f880650 100644 --- a/anchor-counter/yarn.lock +++ b/anchor-counter/yarn.lock @@ -76,11 +76,13 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" -"@magicblock-labs/ephemeral-rollups-sdk@0.8.8": - version "0.8.8" - resolved "https://registry.yarnpkg.com/@magicblock-labs/ephemeral-rollups-sdk/-/ephemeral-rollups-sdk-0.8.8.tgz#5df525ceedf1a667d0f2931f8ddcd83e2c06e062" - integrity sha512-qrhZXSjt4lY3io6pY/VTVkNj2FYGSu/uNwNuT6g3WUFvBVK9pH+enWQHEMSk/f9MsqRbn+prBPCYYVo+1QKMUA== +"@magicblock-labs/ephemeral-rollups-sdk@0.11.1": + version "0.11.1" + resolved "https://registry.yarnpkg.com/@magicblock-labs/ephemeral-rollups-sdk/-/ephemeral-rollups-sdk-0.11.1.tgz#cfc8eb49b625e1f8971cbde7de474f4c39f381c9" + integrity sha512-4z0uFiCqpjUqdbavTVenvSdrLp4DD6EIcvlDYhwl6MMevogj9yrW9w0epyDigyB0xcGW2YH3C4ObzZ6H1a6o3w== dependencies: + "@noble/curves" "^1.4.2" + "@noble/hashes" "^1.4.0" "@phala/dcap-qvl" "^0.3.9" "@solana/web3.js" "^1.98.0" bs58 "^6.0.0" @@ -1041,16 +1043,7 @@ stream-json@^1.9.1: dependencies: stream-chain "^2.2.5" -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -1068,14 +1061,7 @@ string-width@^5.0.1, string-width@^5.1.2: emoji-regex "^9.2.2" strip-ansi "^7.0.1" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -1219,16 +1205,7 @@ workerpool@^9.2.0: resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-9.3.4.tgz#f6c92395b2141afd78e2a889e80cb338fe9fca41" integrity sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== diff --git a/fullstack-test.sh b/fullstack-test.sh index dc58726..dcdfc03 100755 --- a/fullstack-test.sh +++ b/fullstack-test.sh @@ -101,7 +101,9 @@ has_anchor_cli_skip_local_validator() { dump_validator_logs() { if [ -f /tmp/ephemeral-validator.log ]; then echo "=== ephemeral-validator log (size=$(wc -c < /tmp/ephemeral-validator.log) bytes) ===" - sed -n '1,200p' /tmp/ephemeral-validator.log + # Strip ANSI escape sequences from TUI output so the log stays readable. + sed -E $'s/\x1b\\[[0-9;?]*[a-zA-Z]//g; s/\x1b[()][AB012]//g' /tmp/ephemeral-validator.log \ + | sed -n '1,200p' fi if [ -f /tmp/mb-test-validator.log ]; then echo "=== mb-test-validator log (size=$(wc -c < /tmp/mb-test-validator.log) bytes) ===" @@ -287,9 +289,13 @@ if [ "$CLUSTER" = "localnet" ]; then fi exit 1 fi + # commitment=processed reports the latest slot the bank has processed, + # so we see slot>0 within ~1s instead of waiting ~15s for finalization. + # `sed -nE` is portable across BSD sed (macOS) and GNU sed (Linux/CI); + # plain BRE `\+` silently fails on BSD sed and never extracts a value. slot=$(curl -s --max-time 1 -X POST -H "content-type: application/json" \ - -d '{"jsonrpc":"2.0","method":"getSlot","id":1}' http://127.0.0.1:8899 2>/dev/null \ - | sed -n 's/.*"result":\([0-9]\+\).*/\1/p') + -d '{"jsonrpc":"2.0","method":"getSlot","params":[{"commitment":"processed"}],"id":1}' http://127.0.0.1:8899 2>/dev/null \ + | sed -nE 's/.*"result":([0-9]+).*/\1/p') if [ -n "$slot" ] && [ "$slot" -gt 0 ]; then echo -e "${GREEN}solana-test-validator is ready (slot=$slot)${NC}" [ -t 1 ] && stty sane < /dev/tty 2>/dev/null || true @@ -314,14 +320,25 @@ if [ "$CLUSTER" = "localnet" ]; then # Try to get the PID of the running validator EPHEMERAL_VALIDATOR_PID=$(lsof -ti :7799 | head -1) else - # Start ephemeral-validator + # Start ephemeral-validator. 0.8.x ships a mandatory ratatui/crossterm TUI; + # without a controlling TTY (e.g. when stdout is redirected to a file as in + # CI or when run as a background job), crossterm's alternate-screen setup + # fails and the binary exits silently with code 0 before opening port 7799. + # Wrap in a pty via python3 so the validator sees a real terminal; the TUI + # ANSI escape codes go into the log file (which is fine for diagnostics). echo -e "[SETUP] ${GREEN}Starting ephemeral-validator...${NC}" - RUST_LOG=info ephemeral-validator \ - --remotes "http://127.0.0.1:8899" \ - --remotes "ws://127.0.0.1:8900" \ - -l "127.0.0.1:7799" \ - --reset \ - > /tmp/ephemeral-validator.log 2>&1 & + RUST_LOG=info python3 -c ' +import pty, os, sys +status = pty.spawn([ + "ephemeral-validator", + "--remotes", "http://127.0.0.1:8899", + "--remotes", "ws://127.0.0.1:8900", + "-l", "127.0.0.1:7799", + "--reset", + "--lifecycle", "ephemeral", +]) +sys.exit(os.WEXITSTATUS(status) if os.WIFEXITED(status) else 128 + os.WTERMSIG(status)) +' /tmp/ephemeral-validator.log 2>&1 & EPHEMERAL_VALIDATOR_PID=$! EPHEMERAL_VALIDATOR_STARTED_BY_US=true From 7b58f3a988c7005c6f069c75db4daf84f445e49d Mon Sep 17 00:00:00 2001 From: Gabriele Picco Date: Sat, 25 Apr 2026 15:56:07 -0400 Subject: [PATCH 8/9] fix: ci/cd tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Tests construct wsEndpoint by replacing http:// → ws:// while keeping the RPC port. Solana convention uses RPC on port N and WS on N+1, so http://127.0.0.1:8899 was producing ws://127.0.0.1:8899 instead of ws://127.0.0.1:8900, leading to TransactionExpiredTimeoutError when sendAndConfirm couldn't subscribe for confirmation. - Honor explicit WS_ENDPOINT / EPHEMERAL_WS_ENDPOINT / TEE_WS_ENDPOINT env vars and fall back to undefined (web3.js auto-derive, which correctly bumps the port). - Workflow: pass the matching WS env vars so localnet runs subscribe to the right port. --- .github/workflows/test-examples.yml | 1 + anchor-counter/tests/private-counter.ts | 4 ++-- anchor-counter/tests/public-counter.ts | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test-examples.yml b/.github/workflows/test-examples.yml index 11356a1..afac7e9 100644 --- a/.github/workflows/test-examples.yml +++ b/.github/workflows/test-examples.yml @@ -61,6 +61,7 @@ jobs: EPHEMERAL_PROVIDER_ENDPOINT: http://127.0.0.1:7799 EPHEMERAL_WS_ENDPOINT: ws://127.0.0.1:7800 TEE_PROVIDER_ENDPOINT: http://127.0.0.1:7799 + TEE_WS_ENDPOINT: ws://127.0.0.1:7800 ROUTER_ENDPOINT: http://127.0.0.1:7799 run: | sudo prlimit --pid $$ --nofile=1048576:1048576 diff --git a/anchor-counter/tests/private-counter.ts b/anchor-counter/tests/private-counter.ts index 2688a07..c61a80a 100644 --- a/anchor-counter/tests/private-counter.ts +++ b/anchor-counter/tests/private-counter.ts @@ -12,7 +12,7 @@ describe.only("private-counter", () => { let provider = new anchor.AnchorProvider( new anchor.web3.Connection(process.env.PROVIDER_ENDPOINT || "https://api.devnet.solana.com", { - wsEndpoint: process.env.PROVIDER_ENDPOINT?.replace(/^https:\/\//, "wss://").replace(/^http:\/\//, "ws://") || undefined, + wsEndpoint: process.env.WS_ENDPOINT || undefined, commitment: "confirmed", }), anchor.Wallet.local(), @@ -27,7 +27,7 @@ describe.only("private-counter", () => { let providerEphemeralRollup = new anchor.AnchorProvider( new anchor.web3.Connection(ephemeralRpcEndpoint, { - wsEndpoint: process.env.TEE_PROVIDER_ENDPOINT?.replace(/^https:\/\//, "wss://").replace(/^http:\/\//, "ws://") || undefined, + wsEndpoint: process.env.TEE_WS_ENDPOINT || undefined, commitment: "confirmed", }), anchor.Wallet.local(), diff --git a/anchor-counter/tests/public-counter.ts b/anchor-counter/tests/public-counter.ts index dd831ff..821b1da 100644 --- a/anchor-counter/tests/public-counter.ts +++ b/anchor-counter/tests/public-counter.ts @@ -13,7 +13,7 @@ describe("public-counter", () => { new anchor.web3.Connection( process.env.PROVIDER_ENDPOINT || "https://api.devnet.solana.com", { - wsEndpoint: process.env.PROVIDER_ENDPOINT?.replace(/^https:\/\//, "wss://").replace(/^http:\/\//, "ws://") || undefined, + wsEndpoint: process.env.WS_ENDPOINT || undefined, commitment: "confirmed", }, ), @@ -27,7 +27,7 @@ describe("public-counter", () => { "https://devnet-as.magicblock.app/", { wsEndpoint: - process.env.EPHEMERAL_PROVIDER_ENDPOINT?.replace(/^https:\/\//, "wss://").replace(/^http:\/\//, "ws://") || "wss://devnet-as.magicblock.app/", + process.env.EPHEMERAL_WS_ENDPOINT || "wss://devnet-as.magicblock.app/", commitment: "confirmed", }, ), From 5731f2aa2ac27784e45212a57495603cfd8dc1c3 Mon Sep 17 00:00:00 2001 From: Gabriele Picco Date: Sat, 25 Apr 2026 16:08:53 -0400 Subject: [PATCH 9/9] fix: public counter --- .github/workflows/test-examples.yml | 3 --- anchor-counter/tests/private-counter.ts | 2 +- anchor-counter/tests/public-counter.ts | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test-examples.yml b/.github/workflows/test-examples.yml index afac7e9..560393b 100644 --- a/.github/workflows/test-examples.yml +++ b/.github/workflows/test-examples.yml @@ -60,9 +60,6 @@ jobs: WS_ENDPOINT: ws://127.0.0.1:8900 EPHEMERAL_PROVIDER_ENDPOINT: http://127.0.0.1:7799 EPHEMERAL_WS_ENDPOINT: ws://127.0.0.1:7800 - TEE_PROVIDER_ENDPOINT: http://127.0.0.1:7799 - TEE_WS_ENDPOINT: ws://127.0.0.1:7800 - ROUTER_ENDPOINT: http://127.0.0.1:7799 run: | sudo prlimit --pid $$ --nofile=1048576:1048576 cd anchor-counter diff --git a/anchor-counter/tests/private-counter.ts b/anchor-counter/tests/private-counter.ts index c61a80a..17e01a9 100644 --- a/anchor-counter/tests/private-counter.ts +++ b/anchor-counter/tests/private-counter.ts @@ -7,7 +7,7 @@ import * as nacl from "tweetnacl"; const COUNTER_SEED = "counter"; -describe.only("private-counter", () => { +describe("private-counter", () => { console.log("private-counter.ts"); let provider = new anchor.AnchorProvider( diff --git a/anchor-counter/tests/public-counter.ts b/anchor-counter/tests/public-counter.ts index 821b1da..8b908ba 100644 --- a/anchor-counter/tests/public-counter.ts +++ b/anchor-counter/tests/public-counter.ts @@ -6,7 +6,7 @@ import { GetCommitmentSignature } from "@magicblock-labs/ephemeral-rollups-sdk"; const COUNTER_SEED = "counter"; -describe("public-counter", () => { +describe.only("public-counter", () => { console.log("public-counter.ts"); const provider = new anchor.AnchorProvider(