Skip to content

Port studio to genvm-manager (v0.3)#1697

Open
kp2pml30 wants to merge 1 commit into
v0.123-devfrom
feat/genvm-v03-port
Open

Port studio to genvm-manager (v0.3)#1697
kp2pml30 wants to merge 1 commit into
v0.123-devfrom
feat/genvm-v03-port

Conversation

@kp2pml30

@kp2pml30 kp2pml30 commented Jul 1, 2026

Copy link
Copy Markdown
Member

Depends-On: genlayerlabs/genvm-manager#1
Depends-On: https://github.com/genlayerlabs/genlayer-node/pull/1502
Depends-On: https://github.com/genlayerlabs/genlayer-dev-env/pull/95
Depends-On: https://github.com/genlayerlabs/genlayer-e2e/pull/619
Depends-On: #1697
Depends-On: genlayerlabs/genlayer-py#96
Depends-On: genlayerlabs/genlayer-js#192
Depends-On: genlayerlabs/genlayer-testing-suite#98

Ports studio to genvm-manager (v0.3).

NOTE: I did not touch linters, gltest and other stuff

Compatibility with old stuff

  1. I checked that deployed studio is v0.2.16, so in new manager I added version for v0.2.16 with all runners, old layout and other stuff
  2. I changed callldata abi for method call: "method" key became "" so that it's value is prefix of binary calldata
    a. v0.2.16 has a hard remaping for exposing to contracts "method" and giving back only ""
    b. currently manager if sees "method" in input calldata will remap it to "" automatically and print an error
    c. migration of genlayer-js and genlayer-py is needed! migration in node and studio is more or less handled, I believe
  3. code slot changed, this poses issues and I have not supported full v0.3 <-> v0.2 interop, I may need your help
    a. you may be interested in https://github.com/genlayerlabs/genvm-manager/blob/02741163aa89b10331f1585d9ea42868a816945f/docs/website/src/impl-spec/appendix/manager-api.yaml#L256
    b. maybe for real db we can add a field for each contract alongisde storage or whatever

Other notes

there will be hash breaking commit to v0.3 with changing runners for allocating from balance

I have not yet supported builds releasesd and other stuff, as we are not merged into core and not even near that. For that reason I uploaded a hardcoded x86_64 artifact for you builded form commit for convenience

I ran some tests, deployed UI and verified basic functionality working. However, more complicated stuff may not work, it is a draft of changes

@github-actions github-actions Bot changed the base branch from main to v0.123-dev July 1, 2026 15:09
@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

This PR targeted main, which is only the default/static branch.

I retargeted it to v0.123-dev, the active development branch. Pushes to v0.123-dev automatically fast-forward main.

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ffaa2332-d303-4154-856f-23040bd694fd

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Introduces GenVM debug_mode string configuration replacing CLI extra-args, adds ABI root-offset/limit constants, widens fuel integer encoding, restructures fee allocation payloads, switches Docker GenVM installation to a single artifact download, and migrates example/test contracts to gl.contract.Contract API with plain-integer state and updated calldata method-key encoding.

Changes

GenVM Debug Mode, ABI Offsets, and Host Wiring

Layer / File(s) Summary
ABI root offset constants
backend/node/genvm/origin/public_abi.py, backend/node/genvm/__init__.py
Adds _RootOffsets/_TopLimits structures with root_offsets/top_limits Final instances; CODE_SLOT_OFFSET and get_code_slot() now derive from root_offsets.CODE.
Host debug_mode and fuel encoding
backend/node/genvm/origin/base_host.py
run_genvm gains debug_mode/reroute_to params, computes effective_debug_mode, updates the /genvm/run payload, and widens CONSUME_FUEL/REMAINING_FUEL_AS_GEN to 32-byte integers.
run_genvm_host forwarding
backend/node/genvm/base.py
Adds optional debug_mode parameter and forwards it to base_host.run_genvm.
Node base debug mode helper and calldata key
backend/node/base.py, tests/unit/test_genvm_debug_mode_gate.py
Adds _genvm_debug_mode() computing "safe-unbounded"/"disabled" from GENVM_DEBUG_MODE; get_contract_schema/_run_genvm pass debug_mode instead of extra_args; special-method calldata key changes from "method" to "".
Calldata method-key updates in tests
tests/common/request.py, tests/integration/icontracts/tests/test_utf8_roundtrip_contract.py
Test calldata encoding uses empty-string key instead of "method".
Fee allocation payload restructuring
backend/protocol_rpc/fees.py
_genvm_unmetered_message_fee_allocation nests fee params under "Internal"/"External" with renamed fields.
Docker GenVM artifact installation
docker/Dockerfile.backend, docker/Dockerfile.consensus-worker
Replaces per-architecture GitHub downloads with a single GENVM_ARTIFACT_URL tarball extraction and permission adjustments.

gl.contract API Migration Across Contracts

Layer / File(s) Summary
Example contracts migration
examples/contracts/*
Contracts switch to import genlayer as gl, inherit gl.contract.Contract, use gl.TreeMap/gl.DynArray, and replace typed-wrapper state (u256(0)) with plain integers.
Direct/unit/load test contracts migration
tests/direct/contracts/*, tests/direct/storage_read_bench.py, tests/load/contracts/counter.py
Test contracts adopt gl.contract.Contract, plain-int state, and counter.py gains a get_count view method.
Integration icontracts migration
tests/integration/icontracts/contracts/*
Contracts switch base class, use gl.contract.get_at/gl.contract.deploy, namespaced collection types, plain-int state, and genvm_smoke_v1 raises UserError instead of Rollback.
Test harness embedded contracts migration
tests/integration/test_upgrade_contract.py, tests/test_linter_endpoint.py
Embedded contract source strings update imports, base class, and counter/state assignments to plain integers.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Possibly related PRs

Suggested labels: run-tests

Suggested reviewers: cristiam86

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning The PR description gives a summary, but it does not follow the required template or include most required sections like What, Why, Testing done, or Checks. Restructure the description to match the template and add the missing sections, especially issue reference, testing done, decisions made, checks, and release notes.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main migration to genvm-manager v0.3.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/genvm-v03-port

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/node/base.py`:
- Around line 77-85: _align _genvm_debug_mode() with the expected genvm-manager
debug_mode values: the current return values in _genvm_debug_mode() use
"unsafe"/"safe", but the documented and tested modes are "safe-unbounded" and
"disabled". Update the function’s ternary so the true branch returns the
unbounded debug mode and the false branch returns the disabled mode, and make
sure the docstring stays consistent with the values used by the tests and
production behavior._

In `@examples/contracts/tip_jar.py`:
- Around line 8-15: The TipJar constructor is missing the explicit return type
annotation required by the project’s typing convention. Update the __init__
method in TipJar to use a full type-hinted signature like the other methods in
this file and llm_erc20.py, and add the None return annotation without changing
its initialization logic.

In `@tests/integration/icontracts/contracts/company_naming.py`:
- Line 68: The call in company_naming’s contract test uses an invalid SDK
symbol, so revert the rename from run_nondet_default back to the supported gl.vm
API. Update the invocation in the test to use the existing gl.vm.run_nondet or
gl.vm.run_nondet_unsafe symbol that matches the target SDK, and keep the
leader_fn/validator_fn wiring unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9c496360-2c8b-46a6-be0c-4140dda4327e

📥 Commits

Reviewing files that changed from the base of the PR and between 4fde150 and c0af4cd.

📒 Files selected for processing (41)
  • backend/node/base.py
  • backend/node/genvm/__init__.py
  • backend/node/genvm/base.py
  • backend/node/genvm/origin/base_host.py
  • backend/node/genvm/origin/public_abi.py
  • backend/protocol_rpc/fees.py
  • docker/Dockerfile.backend
  • docker/Dockerfile.consensus-worker
  • examples/contracts/_hello_world.py
  • examples/contracts/faucet.py
  • examples/contracts/football_prediction_market.py
  • examples/contracts/llm_erc20.py
  • examples/contracts/log_indexer.py
  • examples/contracts/storage.py
  • examples/contracts/tip_jar.py
  • examples/contracts/user_storage.py
  • examples/contracts/wizard_of_coin.py
  • tests/common/request.py
  • tests/direct/contracts/error_llm_contract_direct.py
  • tests/direct/contracts/error_web_contract_direct.py
  • tests/direct/storage_read_bench.py
  • tests/integration/icontracts/contracts/company_naming.py
  • tests/integration/icontracts/contracts/error_execution_contract.py
  • tests/integration/icontracts/contracts/error_llm_contract.py
  • tests/integration/icontracts/contracts/error_web_contract.py
  • tests/integration/icontracts/contracts/faucet.py
  • tests/integration/icontracts/contracts/genvm_smoke_v1.py
  • tests/integration/icontracts/contracts/intelligent_oracle.py
  • tests/integration/icontracts/contracts/intelligent_oracle_factory.py
  • tests/integration/icontracts/contracts/multi_file_contract/__init__.py
  • tests/integration/icontracts/contracts/multi_file_contract/other.py
  • tests/integration/icontracts/contracts/multi_read_erc20.py
  • tests/integration/icontracts/contracts/multi_tenant_storage.py
  • tests/integration/icontracts/contracts/payable_escrow.py
  • tests/integration/icontracts/contracts/read_erc20.py
  • tests/integration/icontracts/contracts/utf8_roundtrip_contract.py
  • tests/integration/icontracts/tests/test_utf8_roundtrip_contract.py
  • tests/integration/test_upgrade_contract.py
  • tests/load/contracts/counter.py
  • tests/test_linter_endpoint.py
  • tests/unit/test_genvm_debug_mode_gate.py

Comment thread backend/node/base.py
Comment on lines +77 to +85
def _genvm_debug_mode() -> str:
"""genvm-manager `debug_mode` level for the run request.

`unsafe` (dev/stg default) captures unbounded output and enables the
`:latest`/`:test` runner aliases that studio's bundled contracts depend
on; only `unsafe`/`unsafe-tracing` resolve those floating aliases. Prd
sets GENVM_DEBUG_MODE=false -> `disabled` so the aliases fail fast.
"""
return ["--debug-mode"] if _env_bool("GENVM_DEBUG_MODE", default=True) else []
return "unsafe" if _env_bool("GENVM_DEBUG_MODE", default=True) else "safe"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Align _genvm_debug_mode() with the tested manager modes.

Line 85 returns "unsafe"/"safe", but the new unit tests and the docstring expect "safe-unbounded"/"disabled". With GENVM_DEBUG_MODE=false, production would still send "safe" instead of disabling debug mode.

🐛 Proposed fix
-    return "unsafe" if _env_bool("GENVM_DEBUG_MODE", default=True) else "safe"
+    return (
+        "safe-unbounded"
+        if _env_bool("GENVM_DEBUG_MODE", default=True)
+        else "disabled"
+    )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def _genvm_debug_mode() -> str:
"""genvm-manager `debug_mode` level for the run request.
`unsafe` (dev/stg default) captures unbounded output and enables the
`:latest`/`:test` runner aliases that studio's bundled contracts depend
on; only `unsafe`/`unsafe-tracing` resolve those floating aliases. Prd
sets GENVM_DEBUG_MODE=false -> `disabled` so the aliases fail fast.
"""
return ["--debug-mode"] if _env_bool("GENVM_DEBUG_MODE", default=True) else []
return "unsafe" if _env_bool("GENVM_DEBUG_MODE", default=True) else "safe"
def _genvm_debug_mode() -> str:
"""genvm-manager `debug_mode` level for the run request.
`unsafe` (dev/stg default) captures unbounded output and enables the
`:latest`/`:test` runner aliases that studio's bundled contracts depend
on; only `unsafe`/`unsafe-tracing` resolve those floating aliases. Prd
sets GENVM_DEBUG_MODE=false -> `disabled` so the aliases fail fast.
"""
return (
"safe-unbounded"
if _env_bool("GENVM_DEBUG_MODE", default=True)
else "disabled"
)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/node/base.py` around lines 77 - 85, _align _genvm_debug_mode() with
the expected genvm-manager debug_mode values: the current return values in
_genvm_debug_mode() use "unsafe"/"safe", but the documented and tested modes are
"safe-unbounded" and "disabled". Update the function’s ternary so the true
branch returns the unbounded debug mode and the false branch returns the
disabled mode, and make sure the docstring stays consistent with the values used
by the tests and production behavior._

Comment on lines +8 to 15
class TipJar(gl.contract.Contract):
owner: Address
total_tips: u256

def __init__(self):
self.owner = gl.message.sender_address
self.total_tips = u256(0)
self.total_tips = 0

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Missing return type hint on __init__.

Every other method in this file (and llm_erc20.py's __init__) has a full type-hint signature; this __init__ lacks -> None.

🔧 Proposed fix
-    def __init__(self):
+    def __init__(self) -> None:
         self.owner = gl.message.sender_address
         self.total_tips = 0

As per coding guidelines, "Include type hints in all Python code".

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
class TipJar(gl.contract.Contract):
owner: Address
total_tips: u256
def __init__(self):
self.owner = gl.message.sender_address
self.total_tips = u256(0)
self.total_tips = 0
class TipJar(gl.contract.Contract):
owner: Address
total_tips: u256
def __init__(self) -> None:
self.owner = gl.message.sender_address
self.total_tips = 0
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/contracts/tip_jar.py` around lines 8 - 15, The TipJar constructor is
missing the explicit return type annotation required by the project’s typing
convention. Update the __init__ method in TipJar to use a full type-hinted
signature like the other methods in this file and llm_erc20.py, and add the None
return annotation without changing its initialization logic.

Source: Coding guidelines

)

analysis = gl.vm.run_nondet(leader_fn, validator_fn)
analysis = gl.vm.run_nondet_default(leader_fn, validator_fn)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

genlayer SDK v0.3 changelog run_nondet_default gl.vm

💡 Result:

In the GenLayer SDK, there is no documented function named run_nondet_default. The GenVM SDK documentation and API references consistently define two primary functions for executing non-deterministic blocks within the gl.vm module: run_nondet and run_nondet_unsafe [1][2]. Regarding the GenLayer SDK v0.3 changelog, the public record identifies v0.3.0 as having been released on June 4, 2025 [3]. A key feature noted in the v0.3.0 changelog is the ability to decode new leader receipt data [3]. The gl.vm module acts as the core interface for interacting with the GenVM execution environment [4][5][6]. It provides the mechanisms to manage consensus-critical non-deterministic tasks [7][1]. Developers typically use run_nondet_unsafe to execute custom leader/validator logic, which allows for full control over validator error handling and classification, whereas run_nondet is primarily used by built-in convenience functions to automatically handle and compare errors during consensus [1].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Repo files mentioning run_nondet variants:\n'
rg -n --hidden --glob '!**/.git/**' 'run_nondet(_default|_unsafe)?' .

printf '\nRelevant file excerpt:\n'
sed -n '1,140p' tests/integration/icontracts/contracts/company_naming.py

Repository: genlayerlabs/genlayer-studio

Length of output: 1942


gl.vm.run_nondet_default is not a valid SDK symbol
gl.vm exposes run_nondet and run_nondet_unsafe; this rename should be reverted unless the target SDK added a new alias elsewhere. tests/integration/icontracts/contracts/company_naming.py:68

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/integration/icontracts/contracts/company_naming.py` at line 68, The
call in company_naming’s contract test uses an invalid SDK symbol, so revert the
rename from run_nondet_default back to the supported gl.vm API. Update the
invocation in the test to use the existing gl.vm.run_nondet or
gl.vm.run_nondet_unsafe symbol that matches the target SDK, and keep the
leader_fn/validator_fn wiring unchanged.

@kp2pml30 kp2pml30 force-pushed the feat/genvm-v03-port branch from c0af4cd to 145cb7c Compare July 1, 2026 15:31
Comment thread examples/contracts/log_indexer.py Outdated


@allow
@gl.allow

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be @gl.storage.allow

@MuncleUscles

Copy link
Copy Markdown
Member

Re: code slot / v0.2↔v0.3 interop — read your notes, here's the decision.

First: yes, deployed contracts on hosted studio (v0.2.16) have to survive the upgrade. That's the constraint everything below follows from.

Your per-contract metadata suggestion is the right call, and I'd make it explicit rather than inferred from storage. Sniffing the layout can't work: sha3(zeros ++ u32(1)) is CODE in the v0.2 layout but CONTRACT in v0.3 (_RootOffsets), so that address is populated in both layouts with different meanings — presence tells you nothing. Explicit version it is.

Concretely:

  1. genvm_major column on current_state (contract rows), alembic migration backfilling all existing rows to 2 — safe, since everything deployed today is v0.2.16 by definition. Same shape as the old balance column migration; notably we have zero precedent for rewriting the data JSONB itself, and we shouldn't start now.
  2. Stamp new deploys via the manager's POST /contract/detect-version (the manager-api.yaml section you linked) — one canonical version-detection implementation instead of studio growing its own.
  3. Version-keyed layout registry in one module: root_offsets_for(major) / get_code_slot(major), i.e. {2: RootOffsets(CODE=1, …), 3: RootOffsets(MAJOR=0, CONTRACT=1, CODE=2, …)} — no scattered if major == 2 branches.
  4. Thread the contract's major through the six touch points: deploy write (node/base.py::_put_code_to), consensus (consensus/base.pydecisions.py), the upgrade tx type=3 path (worker.py:~1491 — writes the code slot directly, don't miss it), contract_snapshot.py::extract_deployed_code_b64, execution-time storage_read, schema extraction.
  5. No slot migration. v0.2 contracts stay on the v0.2 layout forever and run on the legacy executor you added — rewriting their code into the new slot would break exactly the contracts we're preserving.
  6. The major travels with snapshots/forks/appeal rollback, otherwise a forked v0.2 contract gets read with v0.3 offsets.
  7. Upgrade tx (type=3): cross-major upgrades are rejected. The upgrade path validates the new bytecode via /contract/detect-version against the stored genvm_major and rejects on mismatch with an explicit error — storage is incompatible across majors on both the root layout (same slot addresses, different meanings) and the SDK's own data encoding, so a cross-major upgrade could only silently corrupt. v0.2 contracts remain upgradable with v0.2 code; moving to v0.3 = redeploy. (Separate question: what's the UPGRADERS root slot in v0.3 for — is there an in-band migration story planned for future majors?)

Since v0.3 storage self-describes via the MAJOR slot, this whole thing is a one-time compatibility layer for the pre-MAJOR era — the column is the permanent record for legacy contracts, and everything new is versioned in-band.

Also 👍 on deriving the slot from root_offsets — the old hardcoded b"\x01\x00\x00\x00" next to an unused CODE_SLOT_OFFSET constant was a trap.

@kp2pml30 kp2pml30 force-pushed the feat/genvm-v03-port branch from 4f9f164 to 3697c6a Compare July 8, 2026 14:45
@kp2pml30

kp2pml30 commented Jul 8, 2026

Copy link
Copy Markdown
Member Author

Note on test_llm_invalid_unknown_key (in tests/integration/icontracts/tests/test_error_llm.py):

This test and the rest of test_error_llm.py are identical to the base branch v0.123-dev — this PR only adds a one-line clarifying comment. It is marked @pytest.mark.error_handling, which tests/integration/pytest.ini deselects by default (-m "not error_handling and not gasless"), and no CI job passes -m error_handling on either branch, so it is not exercised by CI here or on base. i.e. the situation is the same on the base branch; nothing about this test is introduced by the port.

When run manually with -m error_handling, it requires UNKNOWN_KEY to be defined in the env (to any non-empty invalid value). If the var is undefined, the v0.3 templater resolves ${ENV[UNKNOWN_KEY]} to "" → provider disabled → zero providers → deploy CANCELED (num_of_rounds=0, no receipt), so the assertion cannot find its receipt. With UNKNOWN_KEY set to a bogus value the provider initializes, the LLM call 401s, and the test passes (ERROR receipt + GenVM internal error in stderr + Leader Timeout) — verified locally.

@sonarqubecloud

sonarqubecloud Bot commented Jul 8, 2026

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
76.8% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants