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}