Skip to content

3.0.0 party 5/6: call stack, snapshots, concurrency, offchain functions, native events - #672

Closed
kubaplas wants to merge 6 commits into
party/4-tooling-examples-cifrom
party/5-late-features
Closed

kubaplas wants to merge 6 commits into
party/4-tooling-examples-cifrom
party/5-late-features

Conversation

@kubaplas

Copy link
Copy Markdown
Contributor

Layer 5 of 6 of the 3.0.0 party stack (bottom-up: 1 → 2 → 3 → 4 → 5 → 6, bottom is #668). Each layer targets the branch below; merge from the bottom. The top of the stack is the tree verified on OdraVM, CasperVM and NCTL; docs are in odradev/odradev.github.io#58 and #59, the migration guide covers every breaking change.

Closes #501, closes #533, closes #544, closes #482, closes #594, closes #538, closes #511.

  • ContractEnv::call_stack() and nth_caller(n): every address from the initiating account to the current contract, the same on OdraVM, CasperVM and livenet getters (Feature request: Traverse callstack #501).
  • HostEnv::take_snapshot() / restore_snapshot(): several test scenarios branch off one setup; OdraVM copies its state, CasperVM points the test builder back at the old state root. On the way: HostEnv::transfer on CasperVM had never worked (Take and restore snapshot #533).
  • CasperClient async API is public; the blocking calls run on one process-wide Tokio runtime and work inside a multi-thread runtime (Remove blocking asyncs from odra livenet #544).
  • HostEnv::concurrently(items, |env, item| ..): worker threads with their own connection and HostEnv on livenet, sequential on the VMs; three deploys on NCTL in the time of one (Async livenet #482). HostRefLoader::load works on OdraVM and CasperVM.
  • #[odra(offchain)]: a &self function that is never deployed and runs on the host against the contract's state; on the HostRef, tested on both VMs (CasperVM gained a livenet-style offline path), listed by odra-cli (CLI-only entrypoints #594).
  • Native events on livenet, recorded from the transactions the environment sends (Implement native events for livenet env #538, Casper 2.0 Native Events #511). The first last_call() after a deploy no longer includes init's events; CallResult::contract_native_events returns native events.
  • HostContext gained take_snapshot/restore_snapshot/thread_env_factory, ContractContext gained call_stack, EntryPoint gained is_offchain (custom backends only).

🤖 Generated with Claude Code

kubaplas and others added 6 commits September 18, 2026 10:17
ContractEnv::call_stack() returns every address from the initiating account to
the current contract, and nth_caller(n) walks it (nth_caller(0) == caller()).
Backed by the Callstack on OdraVM and livenet, and by casper_load_caller_information
on wasm, where the factory frame is skipped so the answer agrees with caller().
Example and test on both VMs in examples/src/features/call_stack.rs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…533)

OdraVM copies the mutable part of its state; CasperVM remembers the post state
hash and points the test builder back at it by committing no effects, plus the
bookkeeping it keeps outside the global state (block time, messages, gas used,
removed validators). Livenet panics. On the way: HostEnv::transfer on CasperVM
built a deploy without payment code and always panicked, it is a native
TransferRequest now.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
#544)

CasperClient no longer owns a runtime: every blocking call is driven by
utils::block_on on a process-wide multi-thread runtime, which also works from
inside a multi-thread Tokio runtime (block_in_place) and refuses a
current-thread one with a clear message. The xxx_async methods are public, so
async code can await them and join several at once. deploy_wasm takes &self.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…#482)

One closure per item, results in item order. The backend decides through
HostContext::thread_env_factory: livenet builds a HostEnv per worker (own
client, same caller and gas), OdraVM and CasperVM run the items one after
another. Deploy in the closure, return the address, load it in the caller's
env; for that, HostRefLoader::load now works on OdraVM (registers the
container if unknown) and CasperVM (no-op) instead of panicking. Tested with
a mocked backend, on both VMs, and on NCTL through the new `concurrent`
scenario of the examples CLI (three deploys in the time of one).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…loyed (#594)

A `&self` function marked offchain stays out of the wasm entry points, the
ContractRef and the schema, and is on the HostRef like any getter. The host
dispatch knows it (EntryPoint::is_offchain), so OdraVM runs it directly,
livenet executes it offline like every getter, and CasperVM gets the same
offline path: CasperHost keeps the entry points of deployed contracts (without
the EntryPointsCaller's HostEnv, which would make the host own itself) and runs
offchain functions in a read-only ContractEnv over the VM's storage. odra-cli
lists them under `contract <Name>` marked as offchain
(SchemaEntrypoints::schema_offchain_entrypoints). Compile errors for &mut self,
trait impls, factory modules and payable/non_reentrant. BalanceBook example,
tested on both VMs and through the CLI on NCTL.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ent sends (#538, #511)

The SSE TransactionProcessed event carries the messages a transaction emitted;
the client keeps them per entity, so native_events_count, get_native_event,
emitted_native_event and last_call() work on livenet as in tests. Casper keeps a
message payload only in its transaction's execution result, so events emitted
earlier or by others are not visible; documented. Verified on NCTL with the
native-events scenario.

Also: the event baseline of a contract is set when it is deployed or loaded, so
the first last_call() after deploy no longer includes init's events (all
backends), and CallResult::contract_native_events returns native events instead
of CES ones.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@kubaplas kubaplas mentioned this pull request Sep 18, 2026
@kubaplas
kubaplas added this pull request to stack #674 September 18, 2026 08:24
@kubaplas
kubaplas removed this pull request from stack #674 September 18, 2026 08:57
@kubaplas

Copy link
Copy Markdown
Contributor Author

Closing: the 3.0.0 party goes back to a single pull request, #664. The commits here are the same work, so nothing is lost.

@kubaplas kubaplas closed this Sep 18, 2026
@kubaplas
kubaplas deleted the party/5-late-features branch September 18, 2026 08:57
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.

1 participant