Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
1db0a61
feat: add v0.6 fee accounting
MuncleUscles Jun 2, 2026
f33d3f8
chore(sync): merge main into studio fees
MuncleUscles Jun 2, 2026
1ecdb6c
fix(ci): update studio test expectations
MuncleUscles Jun 2, 2026
f9bf1b8
fix(ci): sync frontend lock optional peers
MuncleUscles Jun 2, 2026
0683ac9
fix(ci): address studio sonar quality gate
MuncleUscles Jun 2, 2026
22ea139
fix(ci): clear studio sonar annotations
MuncleUscles Jun 2, 2026
b816729
test(studio): assert genvm fee context
MuncleUscles Jun 2, 2026
13a8d53
test(studio): cover message value fee guards
MuncleUscles Jun 2, 2026
5fa9ebf
ci(studio): scope sonar coverage to backend reports
MuncleUscles Jun 2, 2026
397776b
test(studio): cover unbacked external message value
MuncleUscles Jun 2, 2026
7c7a4f0
fix(studio): discard messages after budget exhaustion
MuncleUscles Jun 2, 2026
821b350
feat(studio): show genvm metered message fees
MuncleUscles Jun 2, 2026
773aa31
fix: build studio with matrix genvm tag
MuncleUscles Jun 3, 2026
963f935
fix: require explicit genvm tag for studio builds
MuncleUscles Jun 3, 2026
b88e059
fix: enforce studio fee execution floor
MuncleUscles Jun 4, 2026
161c9f9
feat(fees): integrate v0.122 studio fee accounting
MuncleUscles Jun 4, 2026
e5a3397
chore: sync v0.122-dev with v0.121.4 baseline
MuncleUscles Jun 4, 2026
9e7bd54
feat: restore studio fee accounting on v0.123-dev
MuncleUscles Jun 4, 2026
d34703a
ci: add studio branch policy guard
MuncleUscles Jun 4, 2026
86fde47
[codex] Fix finalization deadlock and surface stuck-head context (#1667)
MuncleUscles Jun 8, 2026
ad77f6b
fix(fees): user-facing money correctness + canonical RPC alignment (#…
MuncleUscles Jun 10, 2026
4fde150
ci: keep main forwarded to active dev branch (#1671)
MuncleUscles Jun 10, 2026
b110df5
fix(ci): default GENVM_TAG for standalone PR builds (#1673)
MuncleUscles Jun 11, 2026
ab62acc
feat(ci): bind GenVM to a branch — source-build path + main host-prot…
MuncleUscles Jun 11, 2026
7a353f1
feat(fees): report time-unit consumption on receipts (unified consume…
MuncleUscles Jun 11, 2026
13348ea
docs: add branching guide (#1675)
MuncleUscles Jun 11, 2026
8d0f902
fix(rpc): gen_getTransactionStatus returns the legacy string again (#…
MuncleUscles Jun 11, 2026
8248c2f
test(ci): gasless-mode integration coverage (#1676)
MuncleUscles Jun 12, 2026
36618ab
fix: keep worker liveness above tx timeout
MuncleUscles Jun 12, 2026
b4b2144
fix: surface stuck finalization health context
MuncleUscles Jun 25, 2026
68b15aa
ci: consume shared GenVM runtime in Studio E2E builds (#1693)
MuncleUscles Jun 25, 2026
cc3bfa6
feat: port v0.121 snapshot pruning, LLM metrics/router, and robustnes…
MuncleUscles Jul 4, 2026
224d3be
fix: bound usage metrics percentages
MuncleUscles Jul 6, 2026
799a495
fix: coalesce duplicate gen_call reads (#1702) (#1703)
MuncleUscles Jul 7, 2026
f799be5
feat(genvm): port studio to genvm-manager v0.3 (#1697)
kp2pml30 Jul 23, 2026
7cec878
fix(pruner): stop declaring Content-Encoding on snapshot archives (#1…
rrabenda Jul 23, 2026
85b8d00
fix(genvm): download GenVM releases instead of building from source (…
MuncleUscles Jul 23, 2026
d7272a9
chore(ci): replace SonarCloud with ruff + Codecov (#1710)
MuncleUscles Jul 23, 2026
c940729
fix: correct defects found while retiring SonarCloud (#1711)
MuncleUscles Jul 23, 2026
2297c1a
fix: preserve serialized receipt errors in usage metrics (#1713)
MuncleUscles Jul 26, 2026
4fca293
fix: preserve exact faucet amounts in wei (#1714)
MuncleUscles Jul 26, 2026
79f81d6
perf(studio): share GenVM service image layers (#1718)
MuncleUscles Jul 31, 2026
c427b1d
chore: fix source builds (#1717)
kp2pml30 Aug 1, 2026
0a30401
chore: add nix cache (#1719)
kp2pml30 Aug 4, 2026
df4f055
feat(consensus): make validator execution concurrency configurable (#…
MuncleUscles Aug 11, 2026
f774d19
ci: skip lint for contracts pinned to the v0.6 fee-era runner (#1725)
MuncleUscles Aug 11, 2026
cccfc70
fix(consensus): appeal claim omits contract_snapshot/consensus_histor…
rasca Aug 13, 2026
d930b53
feat(genvm): calls between different majors of genvm (#1716)
kp2pml30 Aug 14, 2026
93304aa
feat: port contract storage quota to v0.123-dev (#1729)
MuncleUscles Aug 14, 2026
f90d40c
fix: redact validator private keys from RPC (#1731)
MuncleUscles Aug 15, 2026
a15baf3
feat(rate-limit): port read bucket, usage headers and path-based API …
MuncleUscles Aug 18, 2026
5ff1149
chore(genvm): repin to the v1 gl_call ABI and re-vendor origin ⬆️ (#1…
kp2pml30 Aug 24, 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
3 changes: 2 additions & 1 deletion .claude/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"enabledPlugins": {
"code-review@claude-plugins-official": true,
"feature-dev@claude-plugins-official": true,
"hookify@claude-plugins-official": true
"hookify@claude-plugins-official": true,
"sentry@claude-plugins-official": true
}
}
2 changes: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ README.md

docker/
!docker/entrypoint-*.sh
!docker/scripts/
!docker/genvm-source-build.nix.conf
.venv/
.vscode/
.ollama/
Expand Down
1 change: 1 addition & 0 deletions .e2e-genvm-prebuilt/.gitkeep
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

51 changes: 51 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ LOGCONFIG='dev' # dev/prod
LOG_LEVEL='debug' # 'critical', 'error', 'warning', 'info', 'debug', 'trace'
DISABLE_INFO_LOGS_ENDPOINTS='["ping", "eth_getTransactionByHash","gen_getContractSchema", "gen_getContractSchemaForCode", "net_version", "sim_getTransactionsForAddress", "sim_getConsensusContract", "eth_estimateGas", "eth_chainId", "eth_getBlockByNumber", "eth_gasPrice", "sim_getFinalityWindowTime"]'
SHOW_VALIDATOR_PRIVATE_KEYS_IN_LOGS='false' # Set true only when debugging local validator signing.
SHOW_VALIDATOR_PRIVATE_KEYS_IN_RPC='false' # Set true only when inspecting validator signing data locally.

########################################
# JsonRPC Server Configuration
Expand All @@ -36,9 +37,27 @@ REDIS_URL='redis://redis:6379/0' # Redis URL for Socket.IO message queue (e.g.,
# GenVM Configuration
GENVM_BIN="/genvm/bin"
GENVMROOT="/genvm"
# Acquisition mode: prebuilt, source, release, or empty for auto selection.
# Auto precedence is prebuilt E2E tree > <branch>:<commit> source pin > release.
# Release is the default and uses third_party/genvm/version unless GENVM_TAG overrides it.
GENVM_SOURCE_MODE=""
GENVM_TAG="" # Exact release tag, e.g. v0.6.0-rc0. Mutually exclusive with GENVM_REF.
GENVM_REF="" # Source git ref/SHA; set mode=source, or use <branch>:<commit> for auto source mode.
GENVM_EXECUTOR_VERSION_NAME="" # Optional source-build executor label, e.g. v0.3.0-e2e-dev.
NIX_NETRC_FILE="/dev/null" # Netrc with a nix cache pull token; must exist, empty one just means no cache hits.
GENVM_LLM_DEBUG="0"
GENVM_WEB_DEBUG="0"

########################################
# Studio Fee Accounting
# Set all three price values to 0 to run Studio in gasless mode.
GENLAYER_STUDIO_GEN_PER_TIME_UNIT='1000000000000000' # 0.001 GEN per time unit
GENLAYER_STUDIO_STORAGE_UNIT_PRICE='1'
GENLAYER_STUDIO_RECEIPT_GAS_PRICE='1'
GENLAYER_STUDIO_FIXED_PROPOSE_RECEIPT_GAS='210000'
GENLAYER_STUDIO_FIXED_MESSAGE_REVEAL_GAS='100000'
GENLAYER_STUDIO_RECEIPT_WRAPPER_BYTES='1024'

# Ollama Server Configuration
OLAMAPORT='11434'

Expand Down Expand Up @@ -96,12 +115,41 @@ RATE_LIMIT_ENABLED='false' # Enable/disable API key rate limiting
RATE_LIMIT_ANON_PER_MINUTE='30' # Anonymous (no API key) per-minute limit
RATE_LIMIT_ANON_PER_HOUR='500' # Anonymous per-hour limit
RATE_LIMIT_ANON_PER_DAY='5000' # Anonymous per-day limit
RATE_LIMIT_READ_MULTIPLIER='10' # Cheap reads (no GenVM) get this multiple of the tier limits

# PENDING-tx queue depth caps for eth_sendRawTransaction (admission control).
# Empty / unset = no cap (the default for self-hosted). Public shared
# deployments should set both to prevent one user filling the queue.
MAX_PENDING_PER_CONTRACT_DEFAULT='' # Cap PENDING txs per contract (e.g. 50)
MAX_PENDING_PER_SENDER_DEFAULT='' # Cap PENDING txs per sender (e.g. 20)
# Daily per-contract snapshot-byte budget (empty = off). Hosted sandbox
# example: 1073741824 (1 GiB). First write of the UTC day always allowed.
MAX_CONTRACT_SNAPSHOT_BYTES_PER_DAY=''

########################################
# Terminal Contract Snapshot Pruning (Optional)
# Archives terminal transaction contract_snapshot payloads before pruning them
# from the hot transactions table. Disabled by default.
STUDIO_CONTRACT_SNAPSHOT_PRUNER_ENABLED='false'
STUDIO_CONTRACT_SNAPSHOT_PRUNER_ARCHIVE_ENABLED='true'
STUDIO_CONTRACT_SNAPSHOT_PRUNER_VERIFY_ARCHIVE='true'
STUDIO_CONTRACT_SNAPSHOT_PRUNER_ALLOW_LOSSY_PRUNE='false'
STUDIO_CONTRACT_SNAPSHOT_PRUNER_DRY_RUN='false'
STUDIO_CONTRACT_SNAPSHOT_PRUNER_BATCH_SIZE='5'
STUDIO_CONTRACT_SNAPSHOT_PRUNER_RETENTION_HOURS='24'
STUDIO_CONTRACT_SNAPSHOT_PRUNER_INTERVAL_SECONDS='300'
STUDIO_CONTRACT_SNAPSHOT_PRUNER_ARCHIVE_BACKEND='s3' # file, gcs, or s3
STUDIO_CONTRACT_SNAPSHOT_ARCHIVE_RETRIEVAL_ENABLED='false'
STUDIO_CONTRACT_SNAPSHOT_PRUNER_FILE_DIR='data/terminal-contract-snapshot-archive'
STUDIO_CONTRACT_SNAPSHOT_PRUNER_GCS_BUCKET=''
STUDIO_CONTRACT_SNAPSHOT_PRUNER_GCS_PREFIX='studio/terminal-contract-snapshots'
STUDIO_CONTRACT_SNAPSHOT_PRUNER_GCS_STORAGE_CLASS='NEARLINE'
STUDIO_CONTRACT_SNAPSHOT_PRUNER_S3_BUCKET=''
STUDIO_CONTRACT_SNAPSHOT_PRUNER_S3_PREFIX='studio/terminal-contract-snapshots'
STUDIO_CONTRACT_SNAPSHOT_PRUNER_S3_REGION=''
STUDIO_CONTRACT_SNAPSHOT_PRUNER_S3_STORAGE_CLASS='STANDARD'
STUDIO_CONTRACT_SNAPSHOT_PRUNER_S3_SSE='aws:kms'
STUDIO_CONTRACT_SNAPSHOT_PRUNER_S3_KMS_KEY_ID=''

########################################
# Usage Metrics Configuration (Optional)
Expand All @@ -122,6 +170,9 @@ VALIDATORS_CONFIG_JSON='[
JSONRPC_REPLICAS='1'
CONSENSUS_WORKERS='3'
MAX_PARALLEL_TXS_PER_WORKER='1'
# Max validators executing concurrently per transaction (GenVM subprocesses).
# Raise for large committees if memory allows.
CONSENSUS_VALIDATOR_MAX_CONCURRENT='8'
# Production Configuration (for Gunicorn deployment)
WEB_CONCURRENCY='1' # Number of Gunicorn workers (default: CPU cores * 2)
# Service resources limit
Expand Down
Empty file added .genvm-nix-closure/.gitkeep
Empty file.
61 changes: 61 additions & 0 deletions .github/actions/genvm-runners-closure/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: Prebuild GenVM runners closure
description: >
Builds genvm-manager's `runners-all` on the runner, where the Nix sandbox
works, and exports its store closure into the Docker build context so the
in-image source build can import it instead of rebuilding it.

The runner tree is assembled from fixed-output derivations that compile C to
wasm (`genvm-cpython-objs`, `genvm-ffi`, bz2/xz/zlib, numpy, PIL). Their
identity is their output hash, and the `nixos/nix` image cannot enable the
sandbox, so building them there picks up host state and misses the pinned
hashes. Everything else in the build is input-addressed and does not care.

inputs:
ref:
description: GenVM source binding, `<branch>:<commit>` or a bare commit.
required: true
destination:
description: Directory in the build context to write the closure into.
required: false
default: .genvm-nix-closure
nix_cache_pull_token:
description: >-
pull token for the GenLayer nix cache, which is private. A composite
action cannot read `secrets`, so the caller has to thread it through.
Empty means the runner closure is built from source.
required: false
default: ""

outputs:
netrc_path:
description: >-
Netrc holding the cache pull token, written by nix-setup. The Docker
source build fetches from the same cache, so it needs the same credential
— pass it as a BuildKit secret, never as an ARG or a COPY.
value: ${{ steps.nix.outputs.netrc_path }}

runs:
using: composite
steps:
# Substituters, trusted keys and cache auth come from the shared action; the
# sandbox settings below are this action's own and must survive it, so they
# go through extra_nix_config, whose lines are appended last and win.
- name: Install Nix
id: nix
uses: genlayerlabs/github-actions/nix-setup@39b0a0d5e9bb27a1612d2e98b0f8509d31745157
with:
cache_pull_token: ${{ inputs.nix_cache_pull_token }}
extra_nix_config: |
sandbox = true
# Without this Nix quietly builds unsandboxed when it cannot set the
# sandbox up, which is the exact output this action must never export.
sandbox-fallback = false

- name: Build and export runners-all
shell: bash
env:
GENVM_CLOSURE_REF: ${{ inputs.ref }}
GENVM_CLOSURE_DEST: ${{ inputs.destination }}
run: |
./scripts/genvm-runners-closure.sh \
"$GENVM_CLOSURE_REF" "$GENVM_CLOSURE_DEST"
6 changes: 6 additions & 0 deletions .github/scripts/install-python-dependencies.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -euo pipefail

python -m pip install --only-binary :all: -r requirements.txt
python -m pip install --only-binary :all: -r requirements.test.txt
python -m pip install --only-binary :all: -r backend/requirements.txt
105 changes: 105 additions & 0 deletions .github/scripts/validate-branch-policy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#!/usr/bin/env bash
set -euo pipefail

failed=0

error() {
echo "::error::$*" >&2
failed=1
}

warning() {
echo "::warning::$*"
}

active_branch_file="support/ci/ACTIVE_DEV_BRANCH"
if [[ ! -f "${active_branch_file}" ]]; then
error "${active_branch_file} is required."
active_branch=""
else
active_branch="$(tr -d '[:space:]' < "${active_branch_file}")"
fi

if [[ -z "${active_branch}" ]]; then
error "${active_branch_file} must not be empty."
elif [[ "${active_branch}" == "main" ]]; then
error "${active_branch_file} must point to a dev branch, not main."
elif [[ "${active_branch}" != *-dev ]]; then
warning "${active_branch_file} should normally point to a -dev branch; got ${active_branch}."
fi

release_branch="${active_branch%-dev}"
default_branch="${GITHUB_DEFAULT_BRANCH:-}"
event_name="${GITHUB_EVENT_NAME:-local}"
base_ref="${GITHUB_BASE_REF:-}"
head_ref="${GITHUB_HEAD_REF:-}"
ref_name="${GITHUB_REF_NAME:-}"
actor="${GITHUB_ACTOR:-}"

if [[ -n "${default_branch}" && "${default_branch}" != "main" ]]; then
warning "Repository default branch should be main after branch-policy rollout; currently ${default_branch}."
fi

if [[ -n "${base_ref}" && "${base_ref}" == "main" ]]; then
warning "PR targets main; retarget-main-prs should move it to ${active_branch}."
fi

if [[ -n "${base_ref}" && -n "${active_branch}" && "${base_ref}" == "${release_branch}" && "${head_ref}" != "${active_branch}" && "${ALLOW_DIRECT_RELEASE_PR:-false}" != "true" ]]; then
error "PRs into ${release_branch} must come from ${active_branch}. Merge feature work into ${active_branch}, then promote ${active_branch} -> ${release_branch}."
fi

if [[ "${event_name}" == "push" && "${ref_name}" == "main" ]]; then
case "${actor}" in
github-actions[bot]|ci-core-e2e-runner[bot])
;;
*)
error "main should only move by automation from ${active_branch}; direct push actor was ${actor:-unknown}."
;;
esac
fi

if [[ ! -f ".github/workflows/fast-forward-main.yaml" ]]; then
error ".github/workflows/fast-forward-main.yaml is required."
fi

if [[ ! -f ".github/workflows/retarget-main-prs.yaml" ]]; then
error ".github/workflows/retarget-main-prs.yaml is required."
fi

if [[ -f ".github/workflows/release-from-main.yml" ]]; then
error ".github/workflows/release-from-main.yml is forbidden. Releases must be tag/version-branch driven."
fi

if [[ -f "release.config.js" ]]; then
error "release.config.js is forbidden in versioned tooling branches; semantic-release-on-main must not be restored."
fi

if [[ -f ".github/workflows/release-from-tag.yml" ]]; then
if ! grep -Fq 'v*.*.*' .github/workflows/release-from-tag.yml; then
error "release-from-tag.yml must trigger only from version tags matching v*.*.*."
fi
if ! grep -Fq 'refs/remotes/origin/${version_branch}' .github/workflows/release-from-tag.yml || \
! grep -Fq 'tag_commit' .github/workflows/release-from-tag.yml || \
! grep -Fq 'branch_head' .github/workflows/release-from-tag.yml; then
error "release-from-tag.yml must verify the tag commit is the current matching version branch head."
fi
fi

if [[ -f ".github/workflows/manual-docker-release.yml" ]]; then
if ! grep -Fq 'expected_branch=' .github/workflows/manual-docker-release.yml; then
error "manual-docker-release.yml must derive and enforce the expected version branch from the tag."
fi
if ! grep -Fq './.github/workflows/release-from-tag.yml' .github/workflows/manual-docker-release.yml; then
error "manual-docker-release.yml must delegate image promotion to release-from-tag.yml."
fi
fi

if [[ "${failed}" -ne 0 ]]; then
exit 1
fi

if [[ -n "${base_ref}" ]]; then
echo "Branch policy ok for PR ${head_ref} -> ${base_ref}; active dev branch is ${active_branch}."
else
echo "Branch policy ok for ${event_name} on ${ref_name:-detached ref}; active dev branch is ${active_branch}."
fi
16 changes: 15 additions & 1 deletion .github/workflows/README.md
Original file line number Diff line number Diff line change
@@ -1 +1,15 @@
# Trigger CI re-run
# Studio CI Notes

`branch-policy.yml` keeps the release-train model explicit:

- independently releasable work may target a stable branch directly
- multi-feature or cross-repo train work goes to the active `*-dev` integration
branch
- promotion PRs into a release branch normally come from the matching `*-dev`
branch, for example `v0.123-dev` into `v0.123`
- `main` is treated as the static/default GitHub branch, not a release surface
- `master`, stale release branches, `release-from-main.yml`, and
`release.config.js` are treated as invalid release surfaces
- releases must go through version tags validated by `release-from-tag.yml`

See `docs/BRANCHING.md` for the contributor-facing branch model.
Loading
Loading