Skip to main content

nub/
personality.rs

1//! Host-side kernel-personality abstraction.
2//!
3//! A *personality* is the pluggable kernel semantics layer that runs on
4//! top of the nub substrate: it defines what published state objects
5//! mean (decoding, validation, content hashing), how invocations
6//! resolve a root object, and what the guest-side kernel does on
7//! ecalls. JAVM's capability system is one personality; nub itself
8//! stays personality-agnostic and moves opaque bytes + 32-byte
9//! [`ObjHash`] keys.
10//!
11//! This module holds the *host-side* half of the abstraction — what
12//! the [`Nub`](crate::Nub) handle needs from a personality. The
13//! guest-side half (`GuestPersonality` — ecall dispatch, state store,
14//! gas sourcing) lives in `nub-arch-x86`, where the execution-lane and
15//! frame-runtime types it references are defined.
16
17use anyhow::Result;
18use nub_arch_x86_abi::InvocationResult;
19use nub_kernel::ObjHash;
20
21/// A kernel personality, from the host's point of view.
22///
23/// The Hyperlight backend needs nothing beyond the guest blob itself
24/// (the wire protocol is already hash + opaque bytes), so the trait
25/// only carries what the in-process backend requires plus a label for
26/// diagnostics.
27pub trait Personality: Send + Sync + 'static {
28    /// Short personality name labeling substrate diagnostics — every
29    /// [`Nub::create_hyperlight`](crate::Nub::create_hyperlight)
30    /// construction error leads with `create_hyperlight[NAME]`.
31    const NAME: &'static str;
32
33    /// The in-process (Local backend) kernel implementation.
34    type Local: LocalKernel + Default + Send + 'static;
35}
36
37/// In-process kernel: the personality's object store + interpreter
38/// wiring, driven directly by the [`Nub`](crate::Nub) Local backend.
39///
40/// One impl per personality. Replaces the historical hard-wired
41/// `Backend::Local { Kernel<LocalArch>, CacheDirectory }` pair.
42pub trait LocalKernel {
43    /// Decode + validate + content-hash `bytes` and insert the object
44    /// into the store. Returns the personality-computed content hash.
45    /// Idempotent re-puts follow the personality's own semantics
46    /// (JAVM: refcount bump).
47    ///
48    /// **Publication is permanent** — a personality obligation that
49    /// spans both backends (this method and the personality's guest
50    /// store alike): once a put succeeds for a hash, the store must
51    /// retain that object for its own lifetime, never evicting it
52    /// under capacity or memory pressure. The Hyperlight backend's
53    /// host-side idempotency cache
54    /// (`nub-host-kvm::MultiUseSandbox::published_blobs`) short-
55    /// circuits re-puts on exactly this assumption; a store that
56    /// evicted a published object would take warm-path hits for
57    /// objects the guest no longer holds, and later invokes would
58    /// fail guest-side with object-not-found even though every
59    /// publish returned `Ok`.
60    fn put_object(&mut self, bytes: &[u8]) -> Result<ObjHash>;
61
62    /// Pre-hashed variant of [`put_object`](Self::put_object): the
63    /// caller already knows the content hash, letting the impl skip
64    /// hashing on idempotent re-puts. Implementations may
65    /// debug-assert the claimed hash.
66    fn put_object_with_hash(&mut self, hash: ObjHash, bytes: &[u8]) -> Result<()>;
67
68    /// Invoke `endpoint` on the object graph rooted at `root`,
69    /// overlaying `args` per the personality's register ABI, bounded
70    /// by `initial_gas`.
71    fn invoke(
72        &mut self,
73        root: ObjHash,
74        endpoint: u32,
75        args: [u64; 4],
76        initial_gas: u64,
77    ) -> Result<InvocationResult>;
78
79    /// Content-addressed root of the current state (the personality
80    /// defines what "root" means; JAVM: hash of the invoking
81    /// `Cap::Instance` after the most recent invocation).
82    fn state_root(&self) -> ObjHash;
83}