Skip to content

direct_deploy fails with calldata decoding error on 0.30.0rc2 (regression from 0.29.2) #113

Open

Description

@Snehal707

Versions: genlayer-test 0.30.0rc2, genlayer-py 0.19.0rc2 (current release candidates as of testing)

Setup: GenVM bundle download confirmed working correctly — 325,563,524 bytes, completed in 1m21s (~3.9 MiB/s), not a network/timeout issue. Bundle caches correctly; direct_deploy no longer hangs on download after the first run.

Result: Deploying even a trivial contract via direct_deploy fails during SDK import, before the contract's constructor runs:

genlayer.py.calldata.DecodingError: unexpected end of memory

Confirmed NOT present on the prior stable release: reverting to genlayer-test 0.29.2 / genlayer-py 0.16.3 and running the identical direct-mode test (fixture-only, then trivial direct_deploy) passes cleanly: 2 passed in 0.24s. This isolates the decoding error specifically to the 0.30.0rc2/0.19.0rc2 pairing — looks like a regression introduced between stable and the current rc.


Related question, not a bug: on stable 0.29.2, direct_deploy supports deploying multiple Python contracts, but cross-contract calls (DeployContract, CallContract, PostMessage) only execute as real calls when a _gl_call_hook is installed, which the source comments describe as "for glsim mode." Without it, direct mode mocks web/LLM calls but has no default real execution path for @gl.evm.contract_interface reads against a separately deployed contract. Is this intended? If there’s a recommended way to exercise real cross-contract/EVM-interface calls in direct mode, a docs pointer would help — currently using Studio mode for that, which is blocked by the issue above.

Happy to share full logs or a minimal repro repo on request.

Activity

  1. ygd58 commented on Sep 11, 2026

    @ygd58

    Tried to reproduce this with the exact reported version pairing and couldn't trigger the error — sharing what I tried in case it helps narrow down what's different in your environment.

    Setup: fresh venv, pip install genlayer-test==0.30.0rc2 genlayer-py==0.19.0rc2 --pre (confirmed exact versions via pip show).

    Tried three variations, all against a trivial contract with "Depends": "py-genlayer:latest":

    1. No-arg constructor, single direct_deploy("Trivial.py") call — passed.
    2. Constructor with an actual arg, direct_deploy("TrivialArgs.py", 42) — passed (this seemed like the most likely trigger for a calldata-decoding error, since a no-arg constructor has essentially nothing to decode).
    3. Your exact scenario shape — a fixture-only test followed by a trivial-deploy test in the same file/session — also passed, 2 passed in 0.12s, timing-wise similar to what you saw on stable.

    None of these hit DecodingError: unexpected end of memory. I traced where message decoding happens in this path — load_contract_class injects the message via _inject_message_to_fd0 into fd 0 before genlayer is imported (comment in the source: "genlayer reads message from fd 0 at import time"), which is the "before the constructor runs" step you mentioned — but I couldn't get that path to fail with straightforward deploys.

    A few things that might help narrow it down further, if you're up for sharing:

    • Full traceback (is the DecodingError raised from inside _inject_message_to_fd0/fd-0 read, or somewhere else during the SDK import — e.g. a schema/ABI generation step)?
    • Was this a genuinely fresh environment (no prior ~/.cache for genvm/genlayer bundles, no earlier pip installs of adjacent versions), or could an older cached GenVM bundle from a different version have been reused?
    • OS/Python version
    • The actual contract file, if it's not sensitive — mine were about as trivial as it gets, so if yours has something more specific (a particular arg type, dataclass, collection, etc.) that could be the actual trigger.

    Happy to try again with more specifics.

  2. Snehal707 commented on Sep 12, 2026

    @Snehal707
    Author

    Follow-up with a narrowed minimal reproducer and full environment details.

    Environment:

    • genlayer-test==0.30.0rc2
    • genlayer-py==0.19.0rc2
    • Python 3.12.3 on WSL/Linux
    • Fresh direct-mode GenVM bundle cache (the previous bundle cache was cleared and re-downloaded)
    • Failure occurs before the constructor executes, while importing the contract module

    The real Governor contract reproduces the same failure, but the smallest probe that reproduced it was a contract with two Address-typed constructor arguments:

    # { "Depends": "py-genlayer:1jb45aa8ynh2a9c9xn3b7qqh8sm5q93hwfp7jqmwsfhh8jpz09h6" }
    from genlayer import *
    
    class AddressProbe(gl.Contract):
        def __init__(self, left: Address, right: Address):
            self.left = left
            self.right = right

    It was deployed with two address arguments through the direct-mode fixture. The temporary probe file was deleted after the test, so the snippet above records the minimal reproducer shape rather than claiming to be a byte-for-byte recovery of that deleted file.

    The relevant traceback is:

    spec.loader.exec_module(module)
      ... tests/_rc2_address_probe.py:6
    class AddressProbe(gl.Contract):
      ... genlayer/gl/__init__.py
    from genlayer._internal.msg import MessageRawType, message_raw as _message_raw_original
      ... genlayer/_internal/msg.py:69
    message_raw = calldata.decode(io.FileIO(0, closefd=False).readall())
      ... genlayer/py/calldata.py:286
    res = impl()
      ... genlayer/py/calldata.py:245
    code = read_uleb128()
      ... genlayer/py/calldata.py:234
    m = fetch_mem(1)[0]
      ... genlayer/py/calldata.py:224
    raise DecodingError('unexpected end of memory')
    genlayer.py.calldata.DecodingError: unexpected end of memory
    
    ImportError: Failed to load contract: unexpected end of memory
    

    This was reproduced with the minimal two-Address constructor and with contracts/governor.py. It was not isolated to DynArray, method count, or contract size. The stable 0.29.2/0.16.3 environment did not show this import-time failure in the earlier direct-mode run.

    The earlier maintainer reproduction with no-arg, integer-arg, and fixture-plus-deploy probes passed, so the remaining distinction appears to be the Address-typed constructor argument path. Please let me know if you need the original temporary probe recreated or any additional environment output.

  3. HusseinAdeiza commented on Sep 28, 2026

    @HusseinAdeiza

    Reproduced on 0.30.0rc2 / 0.19.0rc2. Assigning to myself.

    The trigger isn't Address constructor args. It fails for every shape I tried, including a no-arg contract:

    ImportError: Failed to load contract: unexpected end of memory
    

    Cause: the SDK moved its modules under genlayer.py, but gltest/direct/sdk_compat.py still imported genlayer.calldata / genlayer.types from the package root. That ImportError is swallowed by _inject_message_to_fd0, so the encoded message never reaches fd 0 and the SDK decodes real stdin instead.

    PR incoming.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions