From 6f1592b8758c7524373e989f2a58b05dbf31ee6a Mon Sep 17 00:00:00 2001 From: Ignacio Duart Date: Mon, 9 Mar 2026 13:46:13 +0100 Subject: [PATCH 1/2] feat: add create_delegate host function for delegate-spawned delegates Adds the stdlib side of issue freenet/freenet-core#2833, enabling delegates to create child delegates at runtime via a new V2 host function. Changes: - New error codes: ERR_DEPTH_EXCEEDED, ERR_CREATIONS_EXCEEDED, ERR_INVALID_WASM, ERR_STORE_FAILED - New extern block (freenet_delegate_management) with __frnt__delegate__create_delegate - DelegateCtx::create_delegate() ergonomic wrapper --- rust/src/delegate_host.rs | 86 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/rust/src/delegate_host.rs b/rust/src/delegate_host.rs index 166f539..1390bc8 100644 --- a/rust/src/delegate_host.rs +++ b/rust/src/delegate_host.rs @@ -98,6 +98,14 @@ pub mod error_codes { pub const ERR_MEMORY_BOUNDS: i32 = -9; /// Contract code not registered in the index. pub const ERR_CONTRACT_CODE_NOT_REGISTERED: i32 = -10; + /// Delegate creation depth limit exceeded. + pub const ERR_DEPTH_EXCEEDED: i32 = -20; + /// Per-call delegate creation limit exceeded. + pub const ERR_CREATIONS_EXCEEDED: i32 = -21; + /// Invalid WASM module (failed to construct DelegateContainer). + pub const ERR_INVALID_WASM: i32 = -23; + /// Failed to register delegate in secret/delegate store. + pub const ERR_STORE_FAILED: i32 = -24; } // ============================================================================ @@ -160,6 +168,24 @@ extern "C" { fn __frnt__delegate__subscribe_contract(id_ptr: i64, id_len: i32) -> i64; } +#[cfg(target_family = "wasm")] +#[link(wasm_import_module = "freenet_delegate_management")] +extern "C" { + /// Create a new delegate from WASM code + parameters. + /// Returns 0 on success, negative error code on failure. + /// On success, writes 32 bytes to out_key_ptr and 32 bytes to out_hash_ptr. + fn __frnt__delegate__create_delegate( + wasm_ptr: i64, + wasm_len: i64, + params_ptr: i64, + params_len: i32, + cipher_ptr: i64, + nonce_ptr: i64, + out_key_ptr: i64, + out_hash_ptr: i64, + ) -> i32; +} + // ============================================================================ // DelegateCtx - Unified handle to context, secrets, and contracts // ============================================================================ @@ -183,6 +209,9 @@ extern "C" { /// [`put_contract_state`](Self::put_contract_state), /// [`update_contract_state`](Self::update_contract_state), /// [`subscribe_contract`](Self::subscribe_contract) +/// +/// # Delegate Management Methods (V2) +/// - [`create_delegate`](Self::create_delegate) #[derive(Default)] #[repr(transparent)] pub struct DelegateCtx { @@ -526,6 +555,63 @@ impl DelegateCtx { false } } + + /// Create a new child delegate from WASM bytecode and parameters. + /// + /// This V2 host function allows a delegate to spawn new delegates at runtime. + /// The child delegate is registered in the node's delegate store and secret store + /// with the provided cipher and nonce. + /// + /// Returns `Ok((key_hash, code_hash))` where both are 32-byte arrays identifying + /// the newly created delegate. Returns `Err(error_code)` on failure. + /// + /// # Resource Limits + /// - Maximum creation depth: 4 (prevents fork bombs) + /// - Maximum creations per process() call: 8 + /// + /// # Error Codes + /// - `-1`: Called outside process() context + /// - `-4`: Invalid parameter + /// - `-9`: WASM memory bounds violation + /// - `-20`: Depth limit exceeded + /// - `-21`: Per-call creation limit exceeded + /// - `-23`: Invalid WASM module + /// - `-24`: Store registration failed + pub fn create_delegate( + &mut self, + wasm_code: &[u8], + params: &[u8], + cipher: &[u8; 32], + nonce: &[u8; 24], + ) -> Result<([u8; 32], [u8; 32]), i32> { + #[cfg(target_family = "wasm")] + { + let mut key_buf = [0u8; 32]; + let mut hash_buf = [0u8; 32]; + let result = unsafe { + __frnt__delegate__create_delegate( + wasm_code.as_ptr() as i64, + wasm_code.len() as i64, + params.as_ptr() as i64, + params.len() as i32, + cipher.as_ptr() as i64, + nonce.as_ptr() as i64, + key_buf.as_mut_ptr() as i64, + hash_buf.as_mut_ptr() as i64, + ) + }; + if result == 0 { + Ok((key_buf, hash_buf)) + } else { + Err(result) + } + } + #[cfg(not(target_family = "wasm"))] + { + let _ = (wasm_code, params, cipher, nonce); + Err(error_codes::ERR_NOT_IN_PROCESS) + } + } } impl std::fmt::Debug for DelegateCtx { From e9a452e6a0a2d53f9a6a9f61d656470bac92ba33 Mon Sep 17 00:00:00 2001 From: Ignacio Duart Date: Mon, 9 Mar 2026 14:37:48 +0100 Subject: [PATCH 2/2] build: bump version to 0.2.1 --- rust/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 0f6081f..bddfff6 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "freenet-stdlib" -version = "0.2.0" +version = "0.2.1" edition = "2021" rust-version = "1.80" publish = true