Skip to content
This repository was archived by the owner on Jul 22, 2026. It is now read-only.
This repository was archived by the owner on Jul 22, 2026. It is now read-only.

sandbox: events/storage from a caught failed allow_write_ops sandbox persist — pin or change semantics #329

Description

@dohernandez

Behavior

When a contract runs a sandbox with allow_write_ops=True and the sandboxed callable fails, but the failure is caught by the parent (sandbox catch), every effect the sandboxed code produced before failing — emitted events AND storage writes — persists into the parent execution.

Source: executor/src/wasi/genlayer_sdk.rs, sandbox result handling — after rt::spawn_apply_run returns, the parent unconditionally adopts the sub-VM's state:

self.context.data.accumulator = my_res.vm_data.accumulator;  // events ride the accumulator
self.context.data.storage = my_res.vm_data.storage;

There is no branch on the sub-VM's outcome and no rollback path. The adoption is symmetric (storage and events together), so the model is self-consistent.

Why raise it

  1. It diverges from EVM, where a reverted sub-call's logs are dropped along with its state changes. Cross-ecosystem developers will carry the EVM intuition ("caught revert ⇒ no logs") into GenVM and be wrong. If the divergence is intended — and the symmetric adopt suggests it is — it should be documented behavior, not incidental.
  2. No test pins it. tests/cases/stable/py/events/ has no emit-then-raise-in-sandbox fixture, so a future refactor of the sandbox result path could silently flip this semantics either way. Whichever way the team decides, a test should lock it.

Downstream verification: the genlayer-node side hit this while building gen_getLogs e2e (NOD-322/324) and verified the persist-on-caught-failure behavior empirically on the v0.6.0-rc1 bundle (executor v0.3.0-rc7); their analysis concluded intended-by-architecture. Their open question doc: node repo plan .claude/plans/nod-322-gen-events-rpc.md §8 OQ10.

Proposed test (sketch)

tests/cases/stable/py/events/post_event_sandbox_caught.py: contract method that, inside allow_write_ops=True sandbox, emits gl.chain.Event + writes storage, then raises; parent catches, method returns normally. Golden asserts: the emission IS present in the receipt and the storage write IS visible — pinning today's semantics. If the team instead decides to adopt EVM-style rollback, the same fixture flips to asserting absence (and the change needs a changelog entry + major consideration, since it's consensus-relevant behavior).

Ask

  1. Team bless-or-change the semantics (decision, then doc note in the events section of the python-sdk docs either way).
  2. Add the pinning fixture (needs a Linux build env or CI to validate; happy to write it once the decision lands).

Related: #327 / #328 (same downstream e2e work surfaced both).

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