Skip to content

Exo and Zone API Patterns

Chris Hibbert edited this page Dec 3, 2024 · 3 revisions

Agoric Zone API Quick Guide

This guide provides an overview of key components in the exo API. Please note that this guide may contain simplifications, and you should refer to the official documentation for complete information. e.g., here's SwingSet on Vat Upgrade.

Key Components

zone.mapStore()

  • KV store, similar to native Map
  • Can live on its own or referenced by other exos in the same lexical scope

zone.setStore()

  • unique value store, similar to native Set
  • Can live on its own or referenced by other exos in the same lexical scope

zone.exo()

  • Creates an exo object with methods
  • The exo object itself is Passable, not its individual methods
  • Methods can lexically capture ("close over") stateful data from their scope
  • The preferred way to write a Far function in agoric-sdk. Far is how we mark an object to be exposed for remote interaction.

zone.exoClass()

  • Has an explicit state record
  • Returns a function (typically named makeFoo) that creates instances of the class
  • Initialization:
    • Takes an initialization function with construction parameters
    • This function returns a record used to create the instance's state record
    • The makeFoo function's parameters match the initialization function's parameters

zone.exoClassKit()

  • Similar to zone.exoClass()
  • Kits are multi-faceted (i.e., Record<string, Record<string, Fn>> instead of just Record<string, Fn>)
  • Often, an attenuated version is returned (e.g., kit.holder)
  • Used when two or more exos need to share state, functionality needs to be attenuated, or the instance relies on a handler that must implement a certain interface.

Important Considerations

Durability

Determined by the zone passed to it - typically heap zone or durable zone bound to baggage.

State

All exo state needs to be Passable

Prepare-time Semantics

  • Calls to zone.exo(), zone.exoClass() and zone.exoClassKit() are typically wrapped in prepare functions which need to return synchronously. zone.exo() creates an instance directly, where zone.exoClass() and zone.exoClassKit() return make*() functions for creating an instance of the class.
  • The prepare statements need to return synchronously to satisfy the "prepare in first crank*" constraint - all exos need to be defined before the object receives any incoming message calls from other vats.
    • *"crank" refers to a unit of execution in the SwingSet VM's event loop. It is everything that happens from an empty stack and promise queue to the next empty stack and promise queue. A turn is everything that happens between an empty stack and the next empty stack, for a given vat.

Synchronous Prelude

  • In a previous version of this post, "synchronous prelude" was conflated with "prepare in first crank". Synchronous prelude refers to code that's called before the first await in a function, and is used to explain await safety rules.
  • await null is used in the top-level of functions that rely on synchronous calls before the first await, to ensure an empty stack. Without this, there is no guarantee that the synchronous calls happen promptly.

Originally posted in discussions: https://github.com/Agoric/agoric-sdk/discussions/9651

Clone this wiki locally