Skip to content

feat: add host function API for delegate context and secrets access#49

Merged
iduartgomez merged 8 commits intomainfrom
feat/delegate-host-functions
Feb 4, 2026
Merged

feat: add host function API for delegate context and secrets access#49
iduartgomez merged 8 commits intomainfrom
feat/delegate-host-functions

Conversation

@iduartgomez
Copy link
Contributor

@iduartgomez iduartgomez commented Feb 3, 2026

Summary

This PR adds a cleaner API for delegates to access context and secrets via an opaque DelegateCtx handle passed to the process() function. This eliminates the need for message round-trips (GetSecretRequest/GetSecretResponse) and allows synchronous access during a single process() call.

Breaking Change

DelegateInterface::process signature now takes a DelegateCtx as the first argument:

fn process(
    ctx: &mut DelegateCtx,
    parameters: Parameters<'static>,
    attested: Option<&'static [u8]>,
    message: InboundDelegateMsg,
) -> Result<Vec<OutboundDelegateMsg>, DelegateError>;

API

The DelegateCtx provides unified access to both temporary context and persistent secrets:

Context Methods (temporary state within a batch)

  • ctx.read() - Read current context bytes
  • ctx.write(data) - Write new context bytes
  • ctx.len() - Get context length
  • ctx.clear() - Clear the context

Secret Methods (persistent encrypted storage)

  • ctx.get_secret(key) - Get a secret by key
  • ctx.set_secret(key, value) - Store a secret
  • ctx.has_secret(key) - Check if a secret exists
  • ctx.remove_secret(key) - Remove a secret
  • ctx.get_secret_len(key) - Get secret length without fetching value

Changes

  • Add delegate_host.rs with unified DelegateCtx type
  • Add error_codes module with standardized host function error codes
  • Update DelegateInterface trait signature (breaking change)
  • Update #[delegate] macro to create handle and pass to process()
  • Remove feature gates - DelegateCtx is always available

Example Usage

#[delegate]
impl DelegateInterface for MyDelegate {
    fn process(
        ctx: &mut DelegateCtx,
        _params: Parameters<'static>,
        _attested: Option<&'static [u8]>,
        message: InboundDelegateMsg,
    ) -> Result<Vec<OutboundDelegateMsg>, DelegateError> {
        // Read/write context directly
        let data = ctx.read();
        ctx.write(b"new state");

        // Access secrets synchronously - no round-trip!
        if let Some(key) = ctx.get_secret(b"private_key") {
            // use key...
        }
        ctx.set_secret(b"new_secret", b"value");

        Ok(vec![])
    }
}

Error Codes

Host functions return negative values to indicate errors:

Code Meaning
0 Success
-1 Called outside process() context
-2 Secret not found
-3 Storage operation failed
-4 Invalid parameter
-5 Context too large
-6 Buffer too small

Related

Requires corresponding runtime changes in freenet-core PR #2844 to provide the host functions.

[AI-assisted - Claude]

This adds a new, cleaner API for delegates to access context and secrets
via opaque handles (`DelegateCtx` and `SecretsStore`) passed to the
`process()` function. This eliminates the need for message round-trips
(GetSecretRequest/GetSecretResponse) and allows synchronous access.

Breaking change: `DelegateInterface::process` signature now takes
`ctx: &mut DelegateCtx` and `secrets: &mut SecretsStore` as the first
two parameters.

Changes:
- Add `delegate_host.rs` with `DelegateCtx` and `SecretsStore` types
- Update `DelegateInterface` trait signature
- Update `#[delegate]` macro to create and pass the handles
- Update example delegate to demonstrate the new API
@iduartgomez iduartgomez marked this pull request as ready for review February 3, 2026 17:01
- Add error_codes module with named constants for all error values
- Update __frnt__delegate__ctx_write to return i32 (error code)
- Add __frnt__delegate__get_secret_len host function for querying secret size
- Update SecretsStore::get to use get_secret_len for proper buffer allocation
- Add SecretsStore::get_len method for querying secret size
- Export error_codes module from prelude
Simplify the delegate host function API by merging SecretsStore
functionality into DelegateCtx. Delegates now use a single context
parameter that provides access to both:

- Temporary context (read/write/clear)
- Persistent secrets (get_secret/set_secret/has_secret/remove_secret)

The SecretsStore type is retained as a deprecated type alias for
backward compatibility.

Changes:
- Move secret methods (get/set/has/remove) to DelegateCtx
- Update DelegateInterface trait to single ctx parameter
- Update #[delegate] macro to remove secrets parameter
- Deprecate SecretsStore as type alias to DelegateCtx
- Remove legacy DelegateInterface trait (without ctx parameter)
- Remove #[cfg(feature = "contract")] guards from delegate_host
- DelegateCtx is now always available, not feature-gated
@iduartgomez iduartgomez merged commit b26e7ec into main Feb 4, 2026
8 of 9 checks passed
@iduartgomez iduartgomez deleted the feat/delegate-host-functions branch February 4, 2026 08:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant