degenbot.registry.session¶

Python presentation over the Rust session object registry.

The Rust SessionObjectRegistry owns canonical identity for one session’s pools and tokens (ADR-006 D5: one Bot, one chain, one session). A Python PoolRegistry / TokenRegistry is a thin delegate over it: it names an object, Rust decides whether that name is the identity the session already holds, and Python keeps the presentation object — the pool/token companion that wraps live Rust state. The two are different things: a session object is a name, a companion is behaviour, and this module holds the seam between them.

# What stays in Python, and why

The companion cache below is not a second identity authority:

  • an entry can only exist for a key Rust minted (SessionObject.key), so Python cannot invent an identity Rust does not hold;

  • add/get_or_add ask Rust to resolve or get-or-create the identity first, so the duplicate decision is made once, in one place;

  • the cache is keyed by, and only ever looked up with, a key Rust produced — no Python code re-derives a key from an address, a chain id, or a family tag.

It is a cache because companions are Python values: release_python_state and close drop them, and a later build mints a fresh companion for an identity the session still holds.

Module Contents¶

class degenbot.registry.session.SessionCompanion[T]¶

A Python companion paired with the session object that names it.

The handle is kept so a teardown can act on the canonical identity (its address, its family) rather than re-deriving it from the companion.

handle: degenbot._ffi.SessionObject¶
item: T¶
class degenbot.registry.session.SessionObjects(py_bot: degenbot._ffi.Bot)¶

Typed adapter over the session-registry seam of one Bot handle.

Every method is one canonical-identity question or get-or-create, with arguments already typed: hex strings and family tags in, a session object handle (or None for a resolve miss) out. No state lives here — the registry behind the handle is the session’s one registry.

get_or_create_pool(*, chain_id: int, family: str, address: str, pool_id: bytes | None = None) → degenbot._ffi.SessionObject¶

Return the session’s canonical pool object, registering it if new.

Parameters:
  • chain_id – The session’s chain; a different chain is refused.

  • family – A registration family tag (“v3”, “balancer-weighted”, …).

  • address – The pool’s address, or its PoolManager when family is “v4”.

  • pool_id – The on-chain V4 pool id; required for “v4” and refused for every other family.

Returns:

The one canonical object for this identity.

resolve_pool(*, chain_id: int, family: str, address: str, pool_id: bytes | None = None) → degenbot._ffi.SessionObject | None¶

Return the session’s canonical pool object for this identity, or None.

Registers nothing.

Returns:

The object, or None when the session does not hold the identity.

resolve_pool_by_address(*, chain_id: int, address: str) → degenbot._ffi.SessionObject | None¶

Return the session’s canonical pool object at address, or None.

The family-agnostic read: it names whichever family registered that address first in this session. A V4 pool is not address-keyed and is never named here.

Returns:

The object, or None when the session holds no address-keyed pool at that address.

get_or_create_token(*, chain_id: int, address: str) → degenbot._ffi.SessionObject¶

Return the session’s canonical token object, registering it if new.

Returns:

The one canonical object for this token identity.

resolve_token(*, chain_id: int, address: str) → degenbot._ffi.SessionObject | None¶

Return the session’s canonical token object for address, or None.

Returns:

The object, or None when the session does not hold it.

counts() → tuple[int, int]¶

Count the session’s canonical objects.

Returns:

(pool_count, token_count) — one entry per identity in this session.

class degenbot.registry.session.CompanionCache[T]¶

The presentation objects this registry hands out, keyed by session key.

Read, store, and drop all take a SessionObject handle, so the only keys that can enter this cache are the ones the Rust registry minted. A miss is None and never a KeyError, so a registry read reads as a question rather than an assertion.

resolve(handle: degenbot._ffi.SessionObject) → T | None¶

Return the companion filed under handle’s identity, if any.

Returns:

The companion, or None when the identity has none filed.

store(handle: degenbot._ffi.SessionObject, item: T) → None¶

File item under handle’s identity, replacing any entry there.

Callers that must not replace use [get_or_store], or check [resolve] first — this is the unconditional write.

get_or_store(handle: degenbot._ffi.SessionObject, item: T) → T¶

File item unless the identity already has a companion; return the canonical one.

The build path’s concurrent-build primitive: a second worker that built the same pool or token gets the companion the first worker registered rather than a twin. setdefault is a single atomic call under the GIL, so racing workers converge on one entry.

Returns:

The filed companion — the existing one on a duplicate, item otherwise.

drop(handle: degenbot._ffi.SessionObject) → None¶

Forget the companion for handle’s identity; a no-op when absent.

entries() → collections.abc.Iterator[SessionCompanion[T]]¶

Iterate the filed companions with the handle that names each.

Returns:

An iterator over one (handle, companion) pair per filed companion, snapshotted so a caller may mutate the cache while iterating.

clear() → None¶

Drop every companion. The session’s identities are untouched.

degenbot.registry.session.pool_family_of(pool: object) → str¶

Read the Rust registration-family tag off a pool companion.

Every pool companion wraps the live Rust handle it was built from, and that handle reports the family the core registered it under — the same tag vocabulary the session registry keys identity by. Reading the tag off the handle (rather than mapping a Python class to a family here) is what keeps a Python consumer from carrying a second, drifting notion of “which family is this pool”.

Returns:

The family tag, e.g. “v3” or “balancer-weighted”.

Raises:

DegenbotValueError – The object carries no live handle, so the session cannot be told which pool it is.