Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
288bddc
perf: optimize explorer contracts page load time
danieljrc888 Mar 19, 2026
cccfdc6
perf: remove contract_snapshot from explorer API responses
danieljrc888 Mar 19, 2026
fa3c3dc
feat: show real tx count on address pages with "View All Transactions…
danieljrc888 Mar 19, 2026
bd70481
fix: always show "Latest N from a total of X transactions" like ether…
danieljrc888 Mar 19, 2026
ead4c71
fix: remove state tab, exclude data from contract detail, fix object …
danieljrc888 Mar 19, 2026
ca28064
style: apply Black formatting to queries.py
danieljrc888 Mar 19, 2026
86c0578
refactor: extract _build_state_row to avoid repeated stats_map lookups
danieljrc888 Mar 19, 2026
093d249
fix: make integration and load tests more deterministic
danieljrc888 Mar 19, 2026
6a7f963
fix: increase load test retry count and delay for contract indexing
danieljrc888 Mar 19, 2026
0d82c2e
fix: add timestamps and flush to load test retry logging
danieljrc888 Mar 19, 2026
50db1c7
fix: address CodeRabbit review comments
danieljrc888 Mar 19, 2026
a03f21b
fix: replace fragile CI polling with Docker healthcheck --wait
danieljrc888 Mar 19, 2026
9582784
fix: increase CI healthcheck tolerance and timeout-minutes
danieljrc888 Mar 19, 2026
c68bf87
fix: create GenVM cache directory before load test compose up
danieljrc888 Mar 19, 2026
5e715f9
fix: increase test retry defaults to handle consensus worker saturation
danieljrc888 Mar 19, 2026
72e9e80
fix: address root causes of flaky CI tests
danieljrc888 Mar 19, 2026
717b03f
style: fix Black formatting in test_state_integrity.py
danieljrc888 Mar 19, 2026
0225162
fix: NULL to_address in advisory lock prevents burn/transfer tx claiming
danieljrc888 Mar 19, 2026
b307457
fix: address CodeRabbit review comments
danieljrc888 Mar 19, 2026
6407e38
feat: add Consensus Result column and tooltip helpers to explorer tables
danieljrc888 Mar 20, 2026
b901657
fix(ci): match load test job name to required status check
danieljrc888 Mar 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 9 additions & 22 deletions .github/workflows/backend_integration_tests_pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,6 @@ jobs:
sed -i "s/VITE_FINALITY_WINDOW=\".*\"/VITE_FINALITY_WINDOW=\"10\"/" .env
sed -i "s/COMPOSE_RPC_CPU_LIMIT=\".*\"/COMPOSE_RPC_CPU_LIMIT=\"4\"/" .env
sed -i "s/COMPOSE_WORKER_CPU_LIMIT=\".*\"/COMPOSE_WORKER_CPU_LIMIT=\"4\"/" .env
sed -i "s/COMPOSE_RPC_MEM_RESERVATION=\".*\"/COMPOSE_RPC_MEM_RESERVATION=\"1\"/" .env
sed -i "s/COMPOSE_WORKER_MEM_RESERVATION=\".*\"/COMPOSE_WORKER_MEM_RESERVATION=\"1\"/" .env
sed -i "s/COMPOSE_RPC_MEM_LIMIT=\".*\"/COMPOSE_RPC_MEM_LIMIT=\"6gb\"/" .env
sed -i "s/COMPOSE_WORKER_MEM_LIMIT=\".*\"/COMPOSE_WORKER_MEM_LIMIT=\"6gb\"/" .env
sed -i "s/COMPOSE_RPC_MEM_RESERVATION=\".*\"/COMPOSE_RPC_MEM_RESERVATION=\"2gb\"/" .env
Expand Down Expand Up @@ -120,29 +118,18 @@ jobs:
consensus-worker.tags=genlayer-studio-consensus-worker:latest
load: true

# Start services without rebuilding images; CI override mounts GenVM precompile cache
# Start services without rebuilding images; CI override provides fast healthcheck timings.
# --wait blocks until all healthchecks pass (jsonrpc /ready + consensus-worker /health).
- name: Run Docker Compose
run: docker compose -f docker-compose.yml -f docker-compose.ci.yml up -d --no-build database-migration jsonrpc consensus-worker

- name: Wait for services to be up
timeout-minutes: 5
run: docker compose -f docker-compose.yml -f docker-compose.ci.yml up -d --no-build --wait database-migration jsonrpc consensus-worker

- name: Verify services are ready
run: |
timeout=60
counter=0
while [[ "$counter" -lt "$timeout" ]]; do
if curl -sS -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"ping","params":[],"id":1}' http://0.0.0.0:4000/api 2>/dev/null | grep -q "OK"; then
echo "RPC server is up!"
break
else
echo "Waiting for RPC server... ($counter/$timeout)"
sleep 2
counter=$((counter+1))
fi
done
if [[ "$counter" -ge "$timeout" ]]; then
echo "Error: Timeout while waiting for RPC server"
exit 1
fi
echo "Services passed healthchecks, verifying RPC endpoint..."
curl -sS -X POST -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"ping","params":[],"id":1}' \
http://0.0.0.0:4000/api

- name: Run tests (parallel)
run: gltest --contracts-dir . --default-wait-retries 140 tests/integration/ -svv -n 8 --ignore=tests/integration/test_validators.py
Expand Down
270 changes: 104 additions & 166 deletions .github/workflows/load-test-oha.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ jobs:
- run: true

load-test:
name: Load Tests
needs: triggers
if: ${{ needs.triggers.outputs.is_pull_request_opened == 'true' || needs.triggers.outputs.is_pull_request_review_approved == 'true' || needs.triggers.outputs.is_pull_request_labeled_with_run_tests == 'true' }}
runs-on: ubuntu-latest
Expand Down Expand Up @@ -84,193 +85,111 @@ jobs:
restore-keys: |
${{ runner.os }}-buildx-

- name: Prepare GenVM cache directory
run: mkdir -p /tmp/genvm-cache/pc && chmod -R 0777 /tmp/genvm-cache

- name: Run Docker Compose with multiple workers
run: docker compose up -d
timeout-minutes: 10
run: docker compose -f docker-compose.yml -f docker-compose.ci.yml up -d --wait
env:
CONSENSUS_WORKERS: 3

- name: Wait for services to be up
- name: Verify services are ready
run: |
echo "Waiting for frontend container to be ready..."
timeout=120
counter=0
frontend_ready=false

# Wait for frontend to be ready
while [[ "$counter" -lt "$timeout" ]]; do
# Check if frontend container logs show it's ready
if docker compose logs frontend 2>/dev/null | tail -20 | grep -q "➜ Local: http://localhost:8080/"; then
echo "✅ Frontend is ready!"
frontend_ready=true
break
else
echo "Waiting for frontend... ($counter/$timeout)"
sleep 5
counter=$((counter+1))
fi
done

if [ "$frontend_ready" = false ]; then
echo "⚠️ Frontend may not be fully ready after $timeout seconds"
echo "Checking if at least the RPC server is responding..."
fi

# Also verify RPC server is responding
echo "Checking RPC server..."
rpc_counter=0
rpc_timeout=60
while [[ "$rpc_counter" -lt "$rpc_timeout" ]]; do
if curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"ping","params":[],"id":1}' http://localhost:4000/api | grep -q "OK"; then
echo "✅ RPC server is up!"
break
else
echo "Waiting for RPC server... ($rpc_counter/$rpc_timeout)"
sleep 5
rpc_counter=$((rpc_counter+1))
fi
done

# Fail if the RPC service didn't start within the timeout
if [[ "$rpc_counter" -ge "$rpc_timeout" ]]; then
echo "Error: Timeout while waiting for RPC server"
docker compose logs
exit 1
fi

# If frontend is ready, we're good to go
if [ "$frontend_ready" = true ]; then
echo "✅ All services are ready!"
else
# If frontend isn't ready but RPC is, wait a bit more
echo "Waiting additional 3 seconds for all services to stabilize..."
sleep 3
fi
echo "Services passed healthchecks, verifying RPC endpoint..."
curl -sS -X POST -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"ping","params":[],"id":1}' \
http://localhost:4000/api

- name: Verify Chain ID
run: |
echo "Verifying chain ID is readable..."
max_retries=5
retry_count=0
chain_id=""

while [[ "$retry_count" -lt "$max_retries" ]]; do
echo "Attempt $((retry_count + 1))/$max_retries to read chain ID..."

# Try to get the chain ID
for attempt in 1 2 3 4 5; do
echo "Attempt $attempt/5..."
response=$(curl -s -X POST http://localhost:4000/api \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "eth_chainId",
"params": [],
"id": 1
}')

-d '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}')
echo "Response: $response"

# Check if we got a valid chain ID response
if echo "$response" | grep -q '"result"'; then
# Handle both formatted and unformatted JSON
chain_id=$(echo "$response" | grep -o '"result"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*"result"[[:space:]]*:[[:space:]]*"//;s/"$//')
if [ ! -z "$chain_id" ]; then
echo "✅ Successfully read chain ID: $chain_id"
break
fi
chain_id=$(python3 -c "import json,sys; r=json.loads(sys.argv[1]); print(r.get('result',''))" "$response" 2>/dev/null || true)
if [ -n "$chain_id" ]; then
echo "Chain ID: $chain_id"
break
fi

retry_count=$((retry_count + 1))

if [[ "$retry_count" -lt "$max_retries" ]]; then
echo "Failed to read chain ID, waiting 10 seconds before retry..."
sleep 10
if [ "$attempt" -lt 5 ]; then
echo "Retrying in 5s..."
sleep 5
fi
done

# Check if we successfully got the chain ID
if [ -z "$chain_id" ]; then
echo "❌ ERROR: Failed to read chain ID after $max_retries attempts"
echo "The blockchain service may not be properly initialized"
echo "ERROR: Failed to read chain ID after 5 attempts"
exit 1
fi

echo "Chain ID verification successful, proceeding with tests..."

- name: Setup validators
run: |
echo "Creating validators with 5 second delays..."
echo "Creating 5 validators with retry logic..."
created=0
for i in {1..5}; do
echo "Creating validator $i/5..."
response=$(curl -s -X POST http://localhost:4000/api \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "sim_createRandomValidator",
"params": [1],
"id": '"$i"'
}')

# Check if creation was successful
if echo "$response" | grep -q '"result"'; then
echo "✅ Validator $i created successfully"
echo "Response: $response"
else
echo "❌ Failed to create validator $i"
echo "Response: $response"
fi

# Wait 5 seconds between validator creation
if [ $i -lt 5 ]; then
echo "Waiting 5 seconds before next validator..."
sleep 5
fi
done
success=false
for attempt in 1 2 3; do
echo "Creating validator $i/5 (attempt $attempt/3)..."
response=$(curl -s -X POST http://localhost:4000/api \
-H "Content-Type: application/json" \
-d "{\"jsonrpc\":\"2.0\",\"method\":\"sim_createRandomValidator\",\"params\":[1],\"id\":$i}")

has_result=$(python3 -c "import json,sys; r=json.loads(sys.argv[1]); print('yes' if 'result' in r else 'no')" "$response" 2>/dev/null || echo "no")
if [ "$has_result" = "yes" ]; then
echo "Validator $i created"
created=$((created + 1))
success=true
break
fi

# Wait for validators to be fully registered
echo "Waiting 10 seconds for validators to be registered..."
sleep 10
echo "Failed: $response"
if [ "$attempt" -lt 3 ]; then
echo "Retrying in 3s..."
sleep 3
fi
done

# Verify validators were created
echo "Verifying validators..."
response=$(curl -s -X POST http://localhost:4000/api \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "sim_countValidators",
"params": [],
"id": 100
}')
if [ "$success" = false ]; then
echo "ERROR: Could not create validator $i after 3 attempts"
exit 1
fi

echo "Count response: $response"
# Brief pause between validators
if [ "$i" -lt 5 ]; then sleep 2; fi
done

# Try different parsing approaches
count=$(echo "$response" | grep -o '"result"[[:space:]]*:[[:space:]]*[0-9]*' | grep -o '[0-9]*' | tail -1)
echo "Waiting 5 seconds for validators to register..."
sleep 5

# If count is empty, try without spaces
if [ -z "$count" ]; then
count=$(echo "$response" | grep -o '"result":[0-9]*' | grep -o '[0-9]*' | tail -1)
fi
# Verify validator count with retry
for attempt in 1 2 3; do
response=$(curl -s -X POST http://localhost:4000/api \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"sim_countValidators","params":[],"id":100}')
count=$(python3 -c "import json,sys; r=json.loads(sys.argv[1]); print(r.get('result',0))" "$response" 2>/dev/null || echo "0")
echo "Validator count: $count (attempt $attempt/3)"

# Default to 0 if still empty
if [ -z "$count" ]; then
count=0
fi
if [ "$count" -ge 5 ]; then
echo "All $count validators registered"
break
fi

echo "Total validators: $count"
if [ "$attempt" -lt 3 ]; then sleep 3; fi
done

if [ "$count" -lt 5 ]; then
echo "❌ Error: Expected at least 5 validators, found $count"
echo "Trying to list all validators for debugging..."
echo "ERROR: Expected at least 5 validators, found $count"
curl -s -X POST http://localhost:4000/api \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "sim_getAllValidators",
"params": [],
"id": 101
}'
-d '{"jsonrpc":"2.0","method":"sim_getAllValidators","params":[],"id":101}'
exit 1
fi
echo "✅ Successfully created $count validators"

- name: Run Load Test - Contract Deploy and Read
run: |
Expand Down Expand Up @@ -497,38 +416,57 @@ jobs:
run: |
echo "Re-creating validators (previous step cleaned them up)..."
for i in {1..5}; do
echo "Creating validator $i/5..."
response=$(curl -s -X POST http://localhost:4000/api \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "sim_createRandomValidator",
"params": [1],
"id": '"$i"'
}')
if echo "$response" | grep -q '"result"'; then
echo "✅ Validator $i created"
else
echo "❌ Failed to create validator $i: $response"
success=false
for attempt in 1 2 3; do
echo "Creating validator $i/5 (attempt $attempt/3)..."
response=$(curl -s -X POST http://localhost:4000/api \
-H "Content-Type: application/json" \
-d "{\"jsonrpc\":\"2.0\",\"method\":\"sim_createRandomValidator\",\"params\":[1],\"id\":$i}")

has_result=$(python3 -c "import json,sys; r=json.loads(sys.argv[1]); print('yes' if 'result' in r else 'no')" "$response" 2>/dev/null || echo "no")
if [ "$has_result" = "yes" ]; then
echo "Validator $i created"
success=true
break
fi

echo "Failed: $response"
if [ "$attempt" -lt 3 ]; then sleep 3; fi
done

if [ "$success" = false ]; then
echo "ERROR: Could not create validator $i after 3 attempts"
exit 1
fi
sleep 2

if [ "$i" -lt 5 ]; then sleep 2; fi
done

echo "Waiting 10 seconds for validators to be registered..."
sleep 10
echo "Waiting 5 seconds for validators to register..."
sleep 5

# Verify validators exist
response=$(curl -s -X POST http://localhost:4000/api \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"sim_countValidators","params":[],"id":100}')
echo "Validator count: $response"
count=$(python3 -c "import json,sys; r=json.loads(sys.argv[1]); print(r.get('result',0))" "$response" 2>/dev/null || echo "0")
echo "Validator count: $count"

if [ "$count" -lt 5 ]; then
echo "ERROR: Expected at least 5 validators, found $count"
exit 1
fi

- name: Run State Integrity Test (lost update detection)
run: |
cd tests/load
pip install genlayer-py requests
python3 test_state_integrity.py http://localhost:4000/api --txs 20

- name: Dump Docker Compose logs
run: docker compose logs
if: failure()

- name: Shutdown Docker Compose
if: always()
run: docker compose down -v
Loading
Loading