pub mod error_codes {
pub const SUCCESS: i32 = 0;
pub const ERR_NOT_IN_PROCESS: i32 = -1;
pub const ERR_SECRET_NOT_FOUND: i32 = -2;
pub const ERR_STORAGE_FAILED: i32 = -3;
pub const ERR_INVALID_PARAM: i32 = -4;
pub const ERR_CONTEXT_TOO_LARGE: i32 = -5;
pub const ERR_BUFFER_TOO_SMALL: i32 = -6;
pub const ERR_CONTRACT_NOT_FOUND: i32 = -7;
pub const ERR_STORE_ERROR: i32 = -8;
pub const ERR_MEMORY_BOUNDS: i32 = -9;
pub const ERR_CONTRACT_CODE_NOT_REGISTERED: i32 = -10;
pub const ERR_DEPTH_EXCEEDED: i32 = -20;
pub const ERR_CREATIONS_EXCEEDED: i32 = -21;
pub const ERR_INVALID_WASM: i32 = -23;
pub const ERR_STORE_FAILED: i32 = -24;
}
#[cfg(target_family = "wasm")]
#[link(wasm_import_module = "freenet_delegate_ctx")]
extern "C" {
fn __frnt__delegate__ctx_len() -> i32;
fn __frnt__delegate__ctx_read(ptr: i64, len: i32) -> i32;
fn __frnt__delegate__ctx_write(ptr: i64, len: i32) -> i32;
}
#[cfg(target_family = "wasm")]
#[link(wasm_import_module = "freenet_delegate_secrets")]
extern "C" {
fn __frnt__delegate__get_secret(key_ptr: i64, key_len: i32, out_ptr: i64, out_len: i32) -> i32;
fn __frnt__delegate__get_secret_len(key_ptr: i64, key_len: i32) -> i32;
fn __frnt__delegate__set_secret(key_ptr: i64, key_len: i32, val_ptr: i64, val_len: i32) -> i32;
fn __frnt__delegate__has_secret(key_ptr: i64, key_len: i32) -> i32;
fn __frnt__delegate__remove_secret(key_ptr: i64, key_len: i32) -> i32;
fn __frnt__delegate__list_secrets_len(prefix_ptr: i64, prefix_len: i32) -> i32;
fn __frnt__delegate__list_secrets(
prefix_ptr: i64,
prefix_len: i32,
out_ptr: i64,
out_len: i32,
) -> i32;
}
#[cfg(target_family = "wasm")]
#[link(wasm_import_module = "freenet_delegate_contracts")]
extern "C" {
fn __frnt__delegate__get_contract_state_len(id_ptr: i64, id_len: i32) -> i64;
fn __frnt__delegate__get_contract_state(
id_ptr: i64,
id_len: i32,
out_ptr: i64,
out_len: i64,
) -> i64;
fn __frnt__delegate__put_contract_state(
id_ptr: i64,
id_len: i32,
state_ptr: i64,
state_len: i64,
) -> i64;
fn __frnt__delegate__update_contract_state(
id_ptr: i64,
id_len: i32,
state_ptr: i64,
state_len: i64,
) -> i64;
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" {
fn __frnt__delegate__create_delegate(
wasm_ptr: i64,
wasm_len: i64,
params_ptr: i64,
params_len: i64,
cipher_ptr: i64,
nonce_ptr: i64,
out_key_ptr: i64,
out_hash_ptr: i64,
) -> i32;
}
#[derive(Default)]
#[repr(transparent)]
pub struct DelegateCtx {
_private: (),
}
impl DelegateCtx {
#[doc(hidden)]
pub unsafe fn __new() -> Self {
Self { _private: () }
}
#[inline]
pub fn len(&self) -> usize {
#[cfg(target_family = "wasm")]
{
let len = unsafe { __frnt__delegate__ctx_len() };
if len < 0 {
0
} else {
len as usize
}
}
#[cfg(not(target_family = "wasm"))]
{
0
}
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn read(&self) -> Vec<u8> {
#[cfg(target_family = "wasm")]
{
let len = unsafe { __frnt__delegate__ctx_len() };
if len <= 0 {
return Vec::new();
}
let mut buf = vec![0u8; len as usize];
let read = unsafe { __frnt__delegate__ctx_read(buf.as_mut_ptr() as i64, len) };
buf.truncate(read.max(0) as usize);
buf
}
#[cfg(not(target_family = "wasm"))]
{
Vec::new()
}
}
pub fn read_into(&self, buf: &mut [u8]) -> usize {
#[cfg(target_family = "wasm")]
{
let read =
unsafe { __frnt__delegate__ctx_read(buf.as_mut_ptr() as i64, buf.len() as i32) };
read.max(0) as usize
}
#[cfg(not(target_family = "wasm"))]
{
let _ = buf;
0
}
}
pub fn write(&mut self, data: &[u8]) -> bool {
#[cfg(target_family = "wasm")]
{
let result =
unsafe { __frnt__delegate__ctx_write(data.as_ptr() as i64, data.len() as i32) };
result == 0
}
#[cfg(not(target_family = "wasm"))]
{
let _ = data;
false
}
}
#[inline]
pub fn clear(&mut self) {
self.write(&[]);
}
pub fn get_secret_len(&self, key: &[u8]) -> Option<usize> {
#[cfg(target_family = "wasm")]
{
let result =
unsafe { __frnt__delegate__get_secret_len(key.as_ptr() as i64, key.len() as i32) };
if result < 0 {
None
} else {
Some(result as usize)
}
}
#[cfg(not(target_family = "wasm"))]
{
let _ = key;
None
}
}
pub fn get_secret(&self, key: &[u8]) -> Option<Vec<u8>> {
#[cfg(target_family = "wasm")]
{
let len = self.get_secret_len(key)?;
if len == 0 {
return Some(Vec::new());
}
let mut out = vec![0u8; len];
let result = unsafe {
__frnt__delegate__get_secret(
key.as_ptr() as i64,
key.len() as i32,
out.as_mut_ptr() as i64,
out.len() as i32,
)
};
if result < 0 {
None
} else {
out.truncate(result as usize);
Some(out)
}
}
#[cfg(not(target_family = "wasm"))]
{
let _ = key;
None
}
}
pub fn set_secret(&mut self, key: &[u8], value: &[u8]) -> bool {
#[cfg(target_family = "wasm")]
{
let result = unsafe {
__frnt__delegate__set_secret(
key.as_ptr() as i64,
key.len() as i32,
value.as_ptr() as i64,
value.len() as i32,
)
};
result == 0
}
#[cfg(not(target_family = "wasm"))]
{
let _ = (key, value);
false
}
}
pub fn has_secret(&self, key: &[u8]) -> bool {
#[cfg(target_family = "wasm")]
{
let result =
unsafe { __frnt__delegate__has_secret(key.as_ptr() as i64, key.len() as i32) };
result == 1
}
#[cfg(not(target_family = "wasm"))]
{
let _ = key;
false
}
}
pub fn remove_secret(&mut self, key: &[u8]) -> bool {
#[cfg(target_family = "wasm")]
{
let result =
unsafe { __frnt__delegate__remove_secret(key.as_ptr() as i64, key.len() as i32) };
result == 0
}
#[cfg(not(target_family = "wasm"))]
{
let _ = key;
false
}
}
pub fn list_secrets(&self, prefix: &[u8]) -> Vec<Vec<u8>> {
#[cfg(target_family = "wasm")]
{
let len = unsafe {
__frnt__delegate__list_secrets_len(prefix.as_ptr() as i64, prefix.len() as i32)
};
if len <= 0 {
return Vec::new();
}
let mut out = vec![0u8; len as usize];
let written = unsafe {
__frnt__delegate__list_secrets(
prefix.as_ptr() as i64,
prefix.len() as i32,
out.as_mut_ptr() as i64,
out.len() as i32,
)
};
if written < 0 {
return Vec::new();
}
out.truncate(written as usize);
decode_secret_key_list(&out)
}
#[cfg(not(target_family = "wasm"))]
{
let _ = prefix;
Vec::new()
}
}
pub fn get_contract_state(&self, instance_id: &[u8; 32]) -> Option<Vec<u8>> {
#[cfg(target_family = "wasm")]
{
let len = unsafe {
__frnt__delegate__get_contract_state_len(instance_id.as_ptr() as i64, 32)
};
if len < 0 {
return None;
}
let len = len as usize;
if len == 0 {
return Some(Vec::new());
}
let mut buf = vec![0u8; len];
let read = unsafe {
__frnt__delegate__get_contract_state(
instance_id.as_ptr() as i64,
32,
buf.as_mut_ptr() as i64,
buf.len() as i64,
)
};
if read < 0 {
None
} else {
buf.truncate(read as usize);
Some(buf)
}
}
#[cfg(not(target_family = "wasm"))]
{
let _ = instance_id;
None
}
}
pub fn put_contract_state(&mut self, instance_id: &[u8; 32], state: &[u8]) -> bool {
#[cfg(target_family = "wasm")]
{
let result = unsafe {
__frnt__delegate__put_contract_state(
instance_id.as_ptr() as i64,
32,
state.as_ptr() as i64,
state.len() as i64,
)
};
result == 0
}
#[cfg(not(target_family = "wasm"))]
{
let _ = (instance_id, state);
false
}
}
pub fn update_contract_state(&mut self, instance_id: &[u8; 32], state: &[u8]) -> bool {
#[cfg(target_family = "wasm")]
{
let result = unsafe {
__frnt__delegate__update_contract_state(
instance_id.as_ptr() as i64,
32,
state.as_ptr() as i64,
state.len() as i64,
)
};
result == 0
}
#[cfg(not(target_family = "wasm"))]
{
let _ = (instance_id, state);
false
}
}
pub fn subscribe_contract(&mut self, instance_id: &[u8; 32]) -> bool {
#[cfg(target_family = "wasm")]
{
let result =
unsafe { __frnt__delegate__subscribe_contract(instance_id.as_ptr() as i64, 32) };
result == 0
}
#[cfg(not(target_family = "wasm"))]
{
let _ = instance_id;
false
}
}
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 i64,
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 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("DelegateCtx")
.field("context_len", &self.len())
.finish_non_exhaustive()
}
}
pub fn encode_secret_key_list<'a, I>(keys: I) -> Vec<u8>
where
I: IntoIterator<Item = &'a [u8]>,
{
let mut buf = Vec::new();
for key in keys {
buf.extend_from_slice(&(key.len() as u32).to_le_bytes());
buf.extend_from_slice(key);
}
buf
}
pub fn decode_secret_key_list(buf: &[u8]) -> Vec<Vec<u8>> {
let mut keys = Vec::new();
let mut pos = 0usize;
while pos + 4 <= buf.len() {
let len = u32::from_le_bytes([buf[pos], buf[pos + 1], buf[pos + 2], buf[pos + 3]]) as usize;
pos += 4;
if pos + len > buf.len() {
break;
}
keys.push(buf[pos..pos + len].to_vec());
pos += len;
}
keys
}
#[cfg(test)]
mod secret_key_list_codec_tests {
use super::{decode_secret_key_list, encode_secret_key_list};
#[test]
fn round_trip_multiple_keys() {
let keys: Vec<&[u8]> = vec![b"room:alice", b"room:bob", b"private_key"];
let encoded = encode_secret_key_list(keys.iter().copied());
let decoded = decode_secret_key_list(&encoded);
assert_eq!(
decoded,
vec![
b"room:alice".to_vec(),
b"room:bob".to_vec(),
b"private_key".to_vec()
]
);
}
#[test]
fn round_trip_empty_list() {
let encoded = encode_secret_key_list(std::iter::empty::<&[u8]>());
assert!(encoded.is_empty());
assert!(decode_secret_key_list(&encoded).is_empty());
}
#[test]
fn round_trip_empty_key() {
let encoded = encode_secret_key_list([b"".as_slice()]);
assert_eq!(encoded, vec![0, 0, 0, 0]);
assert_eq!(decode_secret_key_list(&encoded), vec![Vec::<u8>::new()]);
}
#[test]
fn truncated_trailing_record_is_dropped() {
let mut encoded = encode_secret_key_list([b"abc".as_slice(), b"defgh".as_slice()]);
encoded.truncate(encoded.len() - 2);
assert_eq!(decode_secret_key_list(&encoded), vec![b"abc".to_vec()]);
}
}