Skip to main content

freenet_stdlib/
delegate_interface.rs

1use std::{
2    borrow::{Borrow, Cow},
3    fmt::Display,
4    fs::File,
5    io::Read,
6    ops::Deref,
7    path::Path,
8};
9
10use blake3::{traits::digest::Digest, Hasher as Blake3};
11use serde::{Deserialize, Deserializer, Serialize};
12use serde_with::serde_as;
13
14use crate::generated::client_request::{
15    DelegateKey as FbsDelegateKey, InboundDelegateMsg as FbsInboundDelegateMsg,
16    InboundDelegateMsgType,
17};
18
19use crate::common_generated::common::SecretsId as FbsSecretsId;
20
21use crate::client_api::{TryFromFbs, WsApiError};
22use crate::contract_interface::{RelatedContracts, UpdateData};
23use crate::prelude::{ContractInstanceId, WrappedState};
24use crate::versioning::ContractContainer;
25use crate::{code_hash::CodeHash, prelude::Parameters};
26
27const DELEGATE_HASH_LENGTH: usize = 32;
28
29#[derive(Clone, Debug, Serialize, Deserialize)]
30pub struct Delegate<'a> {
31    #[serde(borrow)]
32    parameters: Parameters<'a>,
33    #[serde(borrow)]
34    pub data: DelegateCode<'a>,
35    key: DelegateKey,
36}
37
38impl Delegate<'_> {
39    pub fn key(&self) -> &DelegateKey {
40        &self.key
41    }
42
43    pub fn code(&self) -> &DelegateCode<'_> {
44        &self.data
45    }
46
47    pub fn code_hash(&self) -> &CodeHash {
48        &self.data.code_hash
49    }
50
51    pub fn params(&self) -> &Parameters<'_> {
52        &self.parameters
53    }
54
55    pub fn into_owned(self) -> Delegate<'static> {
56        Delegate {
57            parameters: self.parameters.into_owned(),
58            data: self.data.into_owned(),
59            key: self.key,
60        }
61    }
62
63    pub fn size(&self) -> usize {
64        self.parameters.size() + self.data.size()
65    }
66
67    pub(crate) fn deserialize_delegate<'de, D>(deser: D) -> Result<Delegate<'static>, D::Error>
68    where
69        D: Deserializer<'de>,
70    {
71        let data: Delegate<'de> = Deserialize::deserialize(deser)?;
72        Ok(data.into_owned())
73    }
74}
75
76impl PartialEq for Delegate<'_> {
77    fn eq(&self, other: &Self) -> bool {
78        self.key == other.key
79    }
80}
81
82impl Eq for Delegate<'_> {}
83
84impl<'a> From<(&DelegateCode<'a>, &Parameters<'a>)> for Delegate<'a> {
85    fn from((data, parameters): (&DelegateCode<'a>, &Parameters<'a>)) -> Self {
86        Self {
87            key: DelegateKey::from_params_and_code(parameters, data),
88            parameters: parameters.clone(),
89            data: data.clone(),
90        }
91    }
92}
93
94/// Executable delegate
95#[derive(Debug, Serialize, Deserialize, Clone)]
96#[serde_as]
97pub struct DelegateCode<'a> {
98    #[serde_as(as = "serde_with::Bytes")]
99    #[serde(borrow)]
100    pub(crate) data: Cow<'a, [u8]>,
101    // todo: skip serializing and instead compute it
102    pub(crate) code_hash: CodeHash,
103}
104
105impl DelegateCode<'static> {
106    /// Loads the contract raw wasm module, without any version.
107    pub fn load_raw(path: &Path) -> Result<Self, std::io::Error> {
108        let contract_data = Self::load_bytes(path)?;
109        Ok(DelegateCode::from(contract_data))
110    }
111
112    pub(crate) fn load_bytes(path: &Path) -> Result<Vec<u8>, std::io::Error> {
113        let mut contract_file = File::open(path)?;
114        let mut contract_data = if let Ok(md) = contract_file.metadata() {
115            Vec::with_capacity(md.len() as usize)
116        } else {
117            Vec::new()
118        };
119        contract_file.read_to_end(&mut contract_data)?;
120        Ok(contract_data)
121    }
122}
123
124impl DelegateCode<'_> {
125    /// Delegate code hash.
126    pub fn hash(&self) -> &CodeHash {
127        &self.code_hash
128    }
129
130    /// Returns the `Base58` string representation of the delegate key.
131    pub fn hash_str(&self) -> String {
132        Self::encode_hash(&self.code_hash.0)
133    }
134
135    /// Reference to delegate code.
136    pub fn data(&self) -> &[u8] {
137        &self.data
138    }
139
140    /// Returns the `Base58` string representation of a hash.
141    pub fn encode_hash(hash: &[u8; DELEGATE_HASH_LENGTH]) -> String {
142        bs58::encode(hash)
143            .with_alphabet(bs58::Alphabet::BITCOIN)
144            .into_string()
145    }
146
147    pub fn into_owned(self) -> DelegateCode<'static> {
148        DelegateCode {
149            code_hash: self.code_hash,
150            data: Cow::from(self.data.into_owned()),
151        }
152    }
153
154    pub fn size(&self) -> usize {
155        self.data.len()
156    }
157}
158
159impl PartialEq for DelegateCode<'_> {
160    fn eq(&self, other: &Self) -> bool {
161        self.code_hash == other.code_hash
162    }
163}
164
165impl Eq for DelegateCode<'_> {}
166
167impl AsRef<[u8]> for DelegateCode<'_> {
168    fn as_ref(&self) -> &[u8] {
169        self.data.borrow()
170    }
171}
172
173impl From<Vec<u8>> for DelegateCode<'static> {
174    fn from(data: Vec<u8>) -> Self {
175        let key = CodeHash::from_code(data.as_slice());
176        DelegateCode {
177            data: Cow::from(data),
178            code_hash: key,
179        }
180    }
181}
182
183impl<'a> From<&'a [u8]> for DelegateCode<'a> {
184    fn from(code: &'a [u8]) -> Self {
185        let key = CodeHash::from_code(code);
186        DelegateCode {
187            data: Cow::from(code),
188            code_hash: key,
189        }
190    }
191}
192
193#[serde_as]
194#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
195pub struct DelegateKey {
196    #[serde_as(as = "[_; DELEGATE_HASH_LENGTH]")]
197    key: [u8; DELEGATE_HASH_LENGTH],
198    code_hash: CodeHash,
199}
200
201impl From<DelegateKey> for SecretsId {
202    fn from(key: DelegateKey) -> SecretsId {
203        SecretsId {
204            hash: key.key,
205            key: vec![],
206        }
207    }
208}
209
210impl DelegateKey {
211    pub const fn new(key: [u8; DELEGATE_HASH_LENGTH], code_hash: CodeHash) -> Self {
212        Self { key, code_hash }
213    }
214
215    fn from_params_and_code<'a>(
216        params: impl Borrow<Parameters<'a>>,
217        wasm_code: impl Borrow<DelegateCode<'a>>,
218    ) -> Self {
219        let code = wasm_code.borrow();
220        let key = generate_id(params.borrow(), code);
221        Self {
222            key,
223            code_hash: *code.hash(),
224        }
225    }
226
227    pub fn encode(&self) -> String {
228        bs58::encode(self.key)
229            .with_alphabet(bs58::Alphabet::BITCOIN)
230            .into_string()
231    }
232
233    pub fn code_hash(&self) -> &CodeHash {
234        &self.code_hash
235    }
236
237    pub fn bytes(&self) -> &[u8] {
238        self.key.as_ref()
239    }
240
241    pub fn from_params(
242        code_hash: impl Into<String>,
243        parameters: &Parameters,
244    ) -> Result<Self, bs58::decode::Error> {
245        let mut code_key = [0; DELEGATE_HASH_LENGTH];
246        bs58::decode(code_hash.into())
247            .with_alphabet(bs58::Alphabet::BITCOIN)
248            .onto(&mut code_key)?;
249        let mut hasher = Blake3::new();
250        hasher.update(code_key.as_slice());
251        hasher.update(parameters.as_ref());
252        let full_key_arr = hasher.finalize();
253
254        debug_assert_eq!(full_key_arr[..].len(), DELEGATE_HASH_LENGTH);
255        let mut key = [0; DELEGATE_HASH_LENGTH];
256        key.copy_from_slice(&full_key_arr);
257
258        Ok(Self {
259            key,
260            code_hash: CodeHash(code_key),
261        })
262    }
263}
264
265impl Deref for DelegateKey {
266    type Target = [u8; DELEGATE_HASH_LENGTH];
267
268    fn deref(&self) -> &Self::Target {
269        &self.key
270    }
271}
272
273impl Display for DelegateKey {
274    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
275        write!(f, "{}", self.encode())
276    }
277}
278
279impl<'a> TryFromFbs<&FbsDelegateKey<'a>> for DelegateKey {
280    fn try_decode_fbs(key: &FbsDelegateKey<'a>) -> Result<Self, WsApiError> {
281        let mut key_bytes = [0; DELEGATE_HASH_LENGTH];
282        key_bytes.copy_from_slice(key.key().bytes().iter().as_ref());
283        Ok(DelegateKey {
284            key: key_bytes,
285            code_hash: CodeHash::from_code(key.code_hash().bytes()),
286        })
287    }
288}
289
290/// Type of errors during interaction with a delegate.
291#[derive(Debug, thiserror::Error, Serialize, Deserialize)]
292pub enum DelegateError {
293    #[error("de/serialization error: {0}")]
294    Deser(String),
295    #[error("{0}")]
296    Other(String),
297}
298
299fn generate_id<'a>(
300    parameters: &Parameters<'a>,
301    code_data: &DelegateCode<'a>,
302) -> [u8; DELEGATE_HASH_LENGTH] {
303    let contract_hash = code_data.hash();
304
305    let mut hasher = Blake3::new();
306    hasher.update(contract_hash.0.as_slice());
307    hasher.update(parameters.as_ref());
308    let full_key_arr = hasher.finalize();
309
310    debug_assert_eq!(full_key_arr[..].len(), DELEGATE_HASH_LENGTH);
311    let mut key = [0; DELEGATE_HASH_LENGTH];
312    key.copy_from_slice(&full_key_arr);
313    key
314}
315
316#[serde_as]
317#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
318pub struct SecretsId {
319    #[serde_as(as = "serde_with::Bytes")]
320    key: Vec<u8>,
321    #[serde_as(as = "[_; 32]")]
322    hash: [u8; 32],
323}
324
325impl SecretsId {
326    pub fn new(key: Vec<u8>) -> Self {
327        let mut hasher = Blake3::new();
328        hasher.update(&key);
329        let hashed = hasher.finalize();
330        let mut hash = [0; 32];
331        hash.copy_from_slice(&hashed);
332        Self { key, hash }
333    }
334
335    pub fn encode(&self) -> String {
336        bs58::encode(self.hash)
337            .with_alphabet(bs58::Alphabet::BITCOIN)
338            .into_string()
339    }
340
341    pub fn hash(&self) -> &[u8; 32] {
342        &self.hash
343    }
344    pub fn key(&self) -> &[u8] {
345        self.key.as_slice()
346    }
347}
348
349impl Display for SecretsId {
350    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
351        write!(f, "{}", self.encode())
352    }
353}
354
355impl<'a> TryFromFbs<&FbsSecretsId<'a>> for SecretsId {
356    fn try_decode_fbs(key: &FbsSecretsId<'a>) -> Result<Self, WsApiError> {
357        let mut key_hash = [0; 32];
358        key_hash.copy_from_slice(key.hash().bytes().iter().as_ref());
359        Ok(SecretsId {
360            key: key.key().bytes().to_vec(),
361            hash: key_hash,
362        })
363    }
364}
365
366/// Identifies where an inbound application message originated from.
367///
368/// When a web app sends a message to a delegate through the WebSocket API with
369/// an authentication token, the runtime resolves the token to the originating
370/// contract and wraps it in `MessageOrigin::WebApp`. Delegates receive this as
371/// the `origin` parameter of [`DelegateInterface::process`].
372#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
373pub enum MessageOrigin {
374    /// The message was sent by a web application backed by the given contract.
375    WebApp(ContractInstanceId),
376}
377
378/// A Delegate is a webassembly code designed to act as an agent for the user on
379/// Freenet. Delegates can:
380///
381///  * Store private data on behalf of the user
382///  * Create, read, and modify contracts
383///  * Create other delegates
384///  * Send and receive messages from other delegates and user interfaces
385///  * Ask the user questions and receive answers
386///
387/// Example use cases:
388///
389///  * A delegate stores a private key for the user, other components can ask
390///    the delegate to sign messages, it will ask the user for permission
391///  * A delegate monitors an inbox contract and downloads new messages when
392///    they arrive
393///
394/// # Example
395///
396/// ```ignore
397/// use freenet_stdlib::prelude::*;
398///
399/// struct MyDelegate;
400///
401/// #[delegate]
402/// impl DelegateInterface for MyDelegate {
403///     fn process(
404///         ctx: &mut DelegateCtx,
405///         _params: Parameters<'static>,
406///         _origin: Option<MessageOrigin>,
407///         message: InboundDelegateMsg,
408///     ) -> Result<Vec<OutboundDelegateMsg>, DelegateError> {
409///         // Access secrets synchronously - no round-trip needed!
410///         if let Some(key) = ctx.get_secret(b"private_key") {
411///             // use key...
412///         }
413///         ctx.set_secret(b"new_key", b"value");
414///
415///         // Read/write context for temporary state within a batch
416///         ctx.write(b"some state");
417///
418///         Ok(vec![])
419///     }
420/// }
421/// ```
422pub trait DelegateInterface {
423    /// Process inbound message, producing zero or more outbound messages in response.
424    ///
425    /// # Arguments
426    /// - `ctx`: Mutable handle to the delegate's execution environment. Provides:
427    ///   - **Context** (temporary): `read()`, `write()`, `len()`, `clear()` - state within a batch
428    ///   - **Secrets** (persistent): `get_secret()`, `set_secret()`, `has_secret()`, `remove_secret()`
429    /// - `parameters`: The delegate's initialization parameters.
430    /// - `origin`: An optional [`MessageOrigin`] identifying where the message came from.
431    ///   For messages sent by web applications, this is `MessageOrigin::WebApp(contract_id)`.
432    /// - `message`: The inbound message to process.
433    fn process(
434        ctx: &mut crate::delegate_host::DelegateCtx,
435        parameters: Parameters<'static>,
436        origin: Option<MessageOrigin>,
437        message: InboundDelegateMsg,
438    ) -> Result<Vec<OutboundDelegateMsg>, DelegateError>;
439}
440
441#[serde_as]
442#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
443pub struct DelegateContext(#[serde_as(as = "serde_with::Bytes")] Vec<u8>);
444
445impl DelegateContext {
446    pub const MAX_SIZE: usize = 4096 * 10 * 10;
447
448    pub fn new(bytes: Vec<u8>) -> Self {
449        assert!(bytes.len() < Self::MAX_SIZE);
450        Self(bytes)
451    }
452
453    pub fn append(&mut self, bytes: &mut Vec<u8>) {
454        assert!(self.0.len() + bytes.len() < Self::MAX_SIZE);
455        self.0.append(bytes)
456    }
457
458    pub fn replace(&mut self, bytes: Vec<u8>) {
459        assert!(bytes.len() < Self::MAX_SIZE);
460        let _ = std::mem::replace(&mut self.0, bytes);
461    }
462}
463
464impl AsRef<[u8]> for DelegateContext {
465    fn as_ref(&self) -> &[u8] {
466        &self.0
467    }
468}
469
470#[derive(Serialize, Deserialize, Debug, Clone)]
471pub enum InboundDelegateMsg<'a> {
472    ApplicationMessage(ApplicationMessage),
473    UserResponse(#[serde(borrow)] UserInputResponse<'a>),
474    GetContractResponse(GetContractResponse),
475    PutContractResponse(PutContractResponse),
476    UpdateContractResponse(UpdateContractResponse),
477    SubscribeContractResponse(SubscribeContractResponse),
478    ContractNotification(ContractNotification),
479    DelegateMessage(DelegateMessage),
480}
481
482impl InboundDelegateMsg<'_> {
483    pub fn into_owned(self) -> InboundDelegateMsg<'static> {
484        match self {
485            InboundDelegateMsg::ApplicationMessage(r) => InboundDelegateMsg::ApplicationMessage(r),
486            InboundDelegateMsg::UserResponse(r) => InboundDelegateMsg::UserResponse(r.into_owned()),
487            InboundDelegateMsg::GetContractResponse(r) => {
488                InboundDelegateMsg::GetContractResponse(r)
489            }
490            InboundDelegateMsg::PutContractResponse(r) => {
491                InboundDelegateMsg::PutContractResponse(r)
492            }
493            InboundDelegateMsg::UpdateContractResponse(r) => {
494                InboundDelegateMsg::UpdateContractResponse(r)
495            }
496            InboundDelegateMsg::SubscribeContractResponse(r) => {
497                InboundDelegateMsg::SubscribeContractResponse(r)
498            }
499            InboundDelegateMsg::ContractNotification(r) => {
500                InboundDelegateMsg::ContractNotification(r)
501            }
502            InboundDelegateMsg::DelegateMessage(r) => InboundDelegateMsg::DelegateMessage(r),
503        }
504    }
505
506    pub fn get_context(&self) -> Option<&DelegateContext> {
507        match self {
508            InboundDelegateMsg::ApplicationMessage(ApplicationMessage { context, .. }) => {
509                Some(context)
510            }
511            InboundDelegateMsg::GetContractResponse(GetContractResponse { context, .. }) => {
512                Some(context)
513            }
514            InboundDelegateMsg::PutContractResponse(PutContractResponse { context, .. }) => {
515                Some(context)
516            }
517            InboundDelegateMsg::UpdateContractResponse(UpdateContractResponse {
518                context, ..
519            }) => Some(context),
520            InboundDelegateMsg::SubscribeContractResponse(SubscribeContractResponse {
521                context,
522                ..
523            }) => Some(context),
524            InboundDelegateMsg::ContractNotification(ContractNotification { context, .. }) => {
525                Some(context)
526            }
527            InboundDelegateMsg::DelegateMessage(DelegateMessage { context, .. }) => Some(context),
528            _ => None,
529        }
530    }
531
532    pub fn get_mut_context(&mut self) -> Option<&mut DelegateContext> {
533        match self {
534            InboundDelegateMsg::ApplicationMessage(ApplicationMessage { context, .. }) => {
535                Some(context)
536            }
537            InboundDelegateMsg::GetContractResponse(GetContractResponse { context, .. }) => {
538                Some(context)
539            }
540            InboundDelegateMsg::PutContractResponse(PutContractResponse { context, .. }) => {
541                Some(context)
542            }
543            InboundDelegateMsg::UpdateContractResponse(UpdateContractResponse {
544                context, ..
545            }) => Some(context),
546            InboundDelegateMsg::SubscribeContractResponse(SubscribeContractResponse {
547                context,
548                ..
549            }) => Some(context),
550            InboundDelegateMsg::ContractNotification(ContractNotification { context, .. }) => {
551                Some(context)
552            }
553            InboundDelegateMsg::DelegateMessage(DelegateMessage { context, .. }) => Some(context),
554            _ => None,
555        }
556    }
557}
558
559impl From<ApplicationMessage> for InboundDelegateMsg<'_> {
560    fn from(value: ApplicationMessage) -> Self {
561        Self::ApplicationMessage(value)
562    }
563}
564
565impl<'a> TryFromFbs<&FbsInboundDelegateMsg<'a>> for InboundDelegateMsg<'a> {
566    fn try_decode_fbs(msg: &FbsInboundDelegateMsg<'a>) -> Result<Self, WsApiError> {
567        match msg.inbound_type() {
568            InboundDelegateMsgType::common_ApplicationMessage => {
569                let app_msg = msg.inbound_as_common_application_message().unwrap();
570                let app_msg = ApplicationMessage {
571                    payload: app_msg.payload().bytes().to_vec(),
572                    context: DelegateContext::new(app_msg.context().bytes().to_vec()),
573                    processed: app_msg.processed(),
574                };
575                Ok(InboundDelegateMsg::ApplicationMessage(app_msg))
576            }
577            InboundDelegateMsgType::UserInputResponse => {
578                let user_response = msg.inbound_as_user_input_response().unwrap();
579                let user_response = UserInputResponse {
580                    request_id: user_response.request_id(),
581                    response: ClientResponse::new(user_response.response().data().bytes().to_vec()),
582                    context: DelegateContext::new(
583                        user_response.delegate_context().bytes().to_vec(),
584                    ),
585                };
586                Ok(InboundDelegateMsg::UserResponse(user_response))
587            }
588            _ => unreachable!("invalid inbound delegate message type"),
589        }
590    }
591}
592
593#[non_exhaustive]
594#[derive(Serialize, Deserialize, Debug, Clone)]
595pub struct ApplicationMessage {
596    pub payload: Vec<u8>,
597    pub context: DelegateContext,
598    pub processed: bool,
599}
600
601impl ApplicationMessage {
602    pub fn new(payload: Vec<u8>) -> Self {
603        Self {
604            payload,
605            context: DelegateContext::default(),
606            processed: false,
607        }
608    }
609
610    pub fn with_context(mut self, context: DelegateContext) -> Self {
611        self.context = context;
612        self
613    }
614
615    pub fn processed(mut self, p: bool) -> Self {
616        self.processed = p;
617        self
618    }
619}
620
621#[derive(Serialize, Deserialize, Debug, Clone)]
622pub struct UserInputResponse<'a> {
623    pub request_id: u32,
624    #[serde(borrow)]
625    pub response: ClientResponse<'a>,
626    pub context: DelegateContext,
627}
628
629impl UserInputResponse<'_> {
630    pub fn into_owned(self) -> UserInputResponse<'static> {
631        UserInputResponse {
632            request_id: self.request_id,
633            response: self.response.into_owned(),
634            context: self.context,
635        }
636    }
637}
638
639#[derive(Serialize, Deserialize, Debug, Clone)]
640pub enum OutboundDelegateMsg {
641    // for the apps
642    ApplicationMessage(ApplicationMessage),
643    RequestUserInput(
644        #[serde(deserialize_with = "OutboundDelegateMsg::deser_user_input_req")]
645        UserInputRequest<'static>,
646    ),
647    // todo: remove when context can be accessed from the delegate environment and we pass it as reference
648    ContextUpdated(DelegateContext),
649    GetContractRequest(GetContractRequest),
650    PutContractRequest(PutContractRequest),
651    UpdateContractRequest(UpdateContractRequest),
652    SubscribeContractRequest(SubscribeContractRequest),
653    SendDelegateMessage(DelegateMessage),
654}
655
656impl From<ApplicationMessage> for OutboundDelegateMsg {
657    fn from(req: ApplicationMessage) -> Self {
658        Self::ApplicationMessage(req)
659    }
660}
661
662impl From<GetContractRequest> for OutboundDelegateMsg {
663    fn from(req: GetContractRequest) -> Self {
664        Self::GetContractRequest(req)
665    }
666}
667
668impl From<PutContractRequest> for OutboundDelegateMsg {
669    fn from(req: PutContractRequest) -> Self {
670        Self::PutContractRequest(req)
671    }
672}
673
674impl From<UpdateContractRequest> for OutboundDelegateMsg {
675    fn from(req: UpdateContractRequest) -> Self {
676        Self::UpdateContractRequest(req)
677    }
678}
679
680impl From<SubscribeContractRequest> for OutboundDelegateMsg {
681    fn from(req: SubscribeContractRequest) -> Self {
682        Self::SubscribeContractRequest(req)
683    }
684}
685
686impl From<DelegateMessage> for OutboundDelegateMsg {
687    fn from(msg: DelegateMessage) -> Self {
688        Self::SendDelegateMessage(msg)
689    }
690}
691
692impl OutboundDelegateMsg {
693    fn deser_user_input_req<'de, D>(deser: D) -> Result<UserInputRequest<'static>, D::Error>
694    where
695        D: serde::Deserializer<'de>,
696    {
697        let value = <UserInputRequest<'de> as Deserialize>::deserialize(deser)?;
698        Ok(value.into_owned())
699    }
700
701    pub fn processed(&self) -> bool {
702        match self {
703            OutboundDelegateMsg::ApplicationMessage(msg) => msg.processed,
704            OutboundDelegateMsg::GetContractRequest(msg) => msg.processed,
705            OutboundDelegateMsg::PutContractRequest(msg) => msg.processed,
706            OutboundDelegateMsg::UpdateContractRequest(msg) => msg.processed,
707            OutboundDelegateMsg::SubscribeContractRequest(msg) => msg.processed,
708            OutboundDelegateMsg::SendDelegateMessage(msg) => msg.processed,
709            OutboundDelegateMsg::RequestUserInput(_) => true,
710            OutboundDelegateMsg::ContextUpdated(_) => true,
711        }
712    }
713
714    pub fn get_context(&self) -> Option<&DelegateContext> {
715        match self {
716            OutboundDelegateMsg::ApplicationMessage(ApplicationMessage { context, .. }) => {
717                Some(context)
718            }
719            OutboundDelegateMsg::GetContractRequest(GetContractRequest { context, .. }) => {
720                Some(context)
721            }
722            OutboundDelegateMsg::PutContractRequest(PutContractRequest { context, .. }) => {
723                Some(context)
724            }
725            OutboundDelegateMsg::UpdateContractRequest(UpdateContractRequest {
726                context, ..
727            }) => Some(context),
728            OutboundDelegateMsg::SubscribeContractRequest(SubscribeContractRequest {
729                context,
730                ..
731            }) => Some(context),
732            OutboundDelegateMsg::SendDelegateMessage(DelegateMessage { context, .. }) => {
733                Some(context)
734            }
735            _ => None,
736        }
737    }
738
739    pub fn get_mut_context(&mut self) -> Option<&mut DelegateContext> {
740        match self {
741            OutboundDelegateMsg::ApplicationMessage(ApplicationMessage { context, .. }) => {
742                Some(context)
743            }
744            OutboundDelegateMsg::GetContractRequest(GetContractRequest { context, .. }) => {
745                Some(context)
746            }
747            OutboundDelegateMsg::PutContractRequest(PutContractRequest { context, .. }) => {
748                Some(context)
749            }
750            OutboundDelegateMsg::UpdateContractRequest(UpdateContractRequest {
751                context, ..
752            }) => Some(context),
753            OutboundDelegateMsg::SubscribeContractRequest(SubscribeContractRequest {
754                context,
755                ..
756            }) => Some(context),
757            OutboundDelegateMsg::SendDelegateMessage(DelegateMessage { context, .. }) => {
758                Some(context)
759            }
760            _ => None,
761        }
762    }
763}
764
765/// Request to get contract state from within a delegate.
766#[derive(Serialize, Deserialize, Debug, Clone)]
767pub struct GetContractRequest {
768    pub contract_id: ContractInstanceId,
769    pub context: DelegateContext,
770    pub processed: bool,
771}
772
773impl GetContractRequest {
774    pub fn new(contract_id: ContractInstanceId) -> Self {
775        Self {
776            contract_id,
777            context: Default::default(),
778            processed: false,
779        }
780    }
781}
782
783/// Response containing contract state for a delegate.
784#[derive(Serialize, Deserialize, Debug, Clone)]
785pub struct GetContractResponse {
786    pub contract_id: ContractInstanceId,
787    /// The contract state, or None if the contract was not found locally.
788    pub state: Option<WrappedState>,
789    pub context: DelegateContext,
790}
791
792/// Request to store a new contract from within a delegate.
793#[derive(Serialize, Deserialize, Debug, Clone)]
794pub struct PutContractRequest {
795    /// The contract code and parameters.
796    pub contract: ContractContainer,
797    /// The initial state for the contract.
798    pub state: WrappedState,
799    /// Related contracts that this contract depends on.
800    #[serde(deserialize_with = "RelatedContracts::deser_related_contracts")]
801    pub related_contracts: RelatedContracts<'static>,
802    /// Context for the delegate.
803    pub context: DelegateContext,
804    /// Whether this request has been processed.
805    pub processed: bool,
806}
807
808impl PutContractRequest {
809    pub fn new(
810        contract: ContractContainer,
811        state: WrappedState,
812        related_contracts: RelatedContracts<'static>,
813    ) -> Self {
814        Self {
815            contract,
816            state,
817            related_contracts,
818            context: Default::default(),
819            processed: false,
820        }
821    }
822}
823
824/// Response after attempting to store a contract from a delegate.
825#[derive(Serialize, Deserialize, Debug, Clone)]
826pub struct PutContractResponse {
827    /// The ID of the contract that was (attempted to be) stored.
828    pub contract_id: ContractInstanceId,
829    /// Success (Ok) or error message (Err).
830    pub result: Result<(), String>,
831    /// Context for the delegate.
832    pub context: DelegateContext,
833}
834
835/// Request to update an existing contract's state from within a delegate.
836#[derive(Serialize, Deserialize, Debug, Clone)]
837pub struct UpdateContractRequest {
838    /// The contract to update.
839    pub contract_id: ContractInstanceId,
840    /// The update to apply (full state or delta).
841    #[serde(deserialize_with = "UpdateContractRequest::deser_update_data")]
842    pub update: UpdateData<'static>,
843    /// Context for the delegate.
844    pub context: DelegateContext,
845    /// Whether this request has been processed.
846    pub processed: bool,
847}
848
849impl UpdateContractRequest {
850    pub fn new(contract_id: ContractInstanceId, update: UpdateData<'static>) -> Self {
851        Self {
852            contract_id,
853            update,
854            context: Default::default(),
855            processed: false,
856        }
857    }
858
859    fn deser_update_data<'de, D>(deser: D) -> Result<UpdateData<'static>, D::Error>
860    where
861        D: Deserializer<'de>,
862    {
863        let value = <UpdateData<'de> as Deserialize>::deserialize(deser)?;
864        Ok(value.into_owned())
865    }
866}
867
868/// Response after attempting to update a contract from a delegate.
869#[derive(Serialize, Deserialize, Debug, Clone)]
870pub struct UpdateContractResponse {
871    /// The contract that was updated.
872    pub contract_id: ContractInstanceId,
873    /// Success (Ok) or error message (Err).
874    pub result: Result<(), String>,
875    /// Context for the delegate.
876    pub context: DelegateContext,
877}
878
879/// Request to subscribe to a contract's state changes from within a delegate.
880#[derive(Serialize, Deserialize, Debug, Clone)]
881pub struct SubscribeContractRequest {
882    /// The contract to subscribe to.
883    pub contract_id: ContractInstanceId,
884    /// Context for the delegate.
885    pub context: DelegateContext,
886    /// Whether this request has been processed.
887    pub processed: bool,
888}
889
890impl SubscribeContractRequest {
891    pub fn new(contract_id: ContractInstanceId) -> Self {
892        Self {
893            contract_id,
894            context: Default::default(),
895            processed: false,
896        }
897    }
898}
899
900/// Response after attempting to subscribe to a contract from a delegate.
901#[derive(Serialize, Deserialize, Debug, Clone)]
902pub struct SubscribeContractResponse {
903    /// The contract subscribed to.
904    pub contract_id: ContractInstanceId,
905    /// Success (Ok) or error message (Err).
906    pub result: Result<(), String>,
907    /// Context for the delegate.
908    pub context: DelegateContext,
909}
910
911/// A message sent from one delegate to another.
912///
913/// Delegates can communicate with each other by emitting
914/// `OutboundDelegateMsg::SendDelegateMessage` with a `DelegateMessage` targeting
915/// another delegate. The runtime delivers it as `InboundDelegateMsg::DelegateMessage`
916/// to the target delegate's `process()` function.
917///
918/// The `sender` field is overwritten by the runtime with the actual sender's key
919/// (sender attestation), so delegates cannot spoof their identity.
920#[derive(Serialize, Deserialize, Debug, Clone)]
921pub struct DelegateMessage {
922    /// The delegate to deliver this message to.
923    pub target: DelegateKey,
924    /// The delegate that sent this message (overwritten by runtime for attestation).
925    pub sender: DelegateKey,
926    /// Arbitrary message payload.
927    pub payload: Vec<u8>,
928    /// Delegate context, carried through the processing pipeline.
929    pub context: DelegateContext,
930    /// Runtime protocol flag indicating whether this message has been delivered.
931    pub processed: bool,
932}
933
934impl DelegateMessage {
935    pub fn new(target: DelegateKey, sender: DelegateKey, payload: Vec<u8>) -> Self {
936        Self {
937            target,
938            sender,
939            payload,
940            context: DelegateContext::default(),
941            processed: false,
942        }
943    }
944}
945
946/// Notification delivered to a delegate when a subscribed contract's state changes.
947#[derive(Serialize, Deserialize, Debug, Clone)]
948pub struct ContractNotification {
949    /// The contract whose state changed.
950    pub contract_id: ContractInstanceId,
951    /// The new state of the contract.
952    pub new_state: WrappedState,
953    /// Context for the delegate.
954    pub context: DelegateContext,
955}
956
957#[serde_as]
958#[derive(Serialize, Deserialize, Debug, Clone)]
959pub struct NotificationMessage<'a>(
960    #[serde_as(as = "serde_with::Bytes")]
961    #[serde(borrow)]
962    Cow<'a, [u8]>,
963);
964
965impl TryFrom<&serde_json::Value> for NotificationMessage<'static> {
966    type Error = ();
967
968    fn try_from(json: &serde_json::Value) -> Result<NotificationMessage<'static>, ()> {
969        // todo: validate format when we have a better idea of what we want here
970        let bytes = serde_json::to_vec(json).unwrap();
971        Ok(Self(Cow::Owned(bytes)))
972    }
973}
974
975impl NotificationMessage<'_> {
976    pub fn into_owned(self) -> NotificationMessage<'static> {
977        NotificationMessage(self.0.into_owned().into())
978    }
979    pub fn bytes(&self) -> &[u8] {
980        self.0.as_ref()
981    }
982}
983
984#[serde_as]
985#[derive(Serialize, Deserialize, Debug, Clone)]
986pub struct ClientResponse<'a>(
987    #[serde_as(as = "serde_with::Bytes")]
988    #[serde(borrow)]
989    Cow<'a, [u8]>,
990);
991
992impl Deref for ClientResponse<'_> {
993    type Target = [u8];
994
995    fn deref(&self) -> &Self::Target {
996        &self.0
997    }
998}
999
1000impl ClientResponse<'_> {
1001    pub fn new(response: Vec<u8>) -> Self {
1002        Self(response.into())
1003    }
1004    pub fn into_owned(self) -> ClientResponse<'static> {
1005        ClientResponse(self.0.into_owned().into())
1006    }
1007    pub fn bytes(&self) -> &[u8] {
1008        self.0.as_ref()
1009    }
1010}
1011
1012#[derive(Serialize, Deserialize, Debug, Clone)]
1013pub struct UserInputRequest<'a> {
1014    pub request_id: u32,
1015    #[serde(borrow)]
1016    /// An interpretable message by the notification system.
1017    pub message: NotificationMessage<'a>,
1018    /// If a response is required from the user they can be chosen from this list.
1019    pub responses: Vec<ClientResponse<'a>>,
1020}
1021
1022impl UserInputRequest<'_> {
1023    pub fn into_owned(self) -> UserInputRequest<'static> {
1024        UserInputRequest {
1025            request_id: self.request_id,
1026            message: self.message.into_owned(),
1027            responses: self.responses.into_iter().map(|r| r.into_owned()).collect(),
1028        }
1029    }
1030}
1031
1032#[doc(hidden)]
1033pub(crate) mod wasm_interface {
1034    //! Contains all the types to interface between the host environment and
1035    //! the wasm module execution.
1036    use super::*;
1037    use crate::memory::WasmLinearMem;
1038
1039    #[repr(C)]
1040    #[derive(Debug, Clone, Copy)]
1041    pub struct DelegateInterfaceResult {
1042        ptr: i64,
1043        size: u32,
1044    }
1045
1046    impl DelegateInterfaceResult {
1047        pub unsafe fn from_raw(ptr: i64, mem: &WasmLinearMem) -> Self {
1048            let result = Box::leak(Box::from_raw(crate::memory::buf::compute_ptr(
1049                ptr as *mut Self,
1050                mem,
1051            )));
1052            #[cfg(feature = "trace")]
1053            {
1054                tracing::trace!(
1055                    "got FFI result @ {ptr} ({:p}) -> {result:?}",
1056                    ptr as *mut Self
1057                );
1058            }
1059            *result
1060        }
1061
1062        #[cfg(feature = "contract")]
1063        pub fn into_raw(self) -> i64 {
1064            #[cfg(feature = "trace")]
1065            {
1066                tracing::trace!("returning FFI -> {self:?}");
1067            }
1068            let ptr = Box::into_raw(Box::new(self));
1069            #[cfg(feature = "trace")]
1070            {
1071                tracing::trace!("FFI result ptr: {ptr:p} ({}i64)", ptr as i64);
1072            }
1073            ptr as _
1074        }
1075
1076        pub unsafe fn unwrap(
1077            self,
1078            mem: WasmLinearMem,
1079        ) -> Result<Vec<OutboundDelegateMsg>, DelegateError> {
1080            let ptr = crate::memory::buf::compute_ptr(self.ptr as *mut u8, &mem);
1081            let serialized = std::slice::from_raw_parts(ptr as *const u8, self.size as _);
1082            let value: Result<Vec<OutboundDelegateMsg>, DelegateError> =
1083                bincode::deserialize(serialized)
1084                    .map_err(|e| DelegateError::Other(format!("{e}")))?;
1085            #[cfg(feature = "trace")]
1086            {
1087                tracing::trace!(
1088                    "got result through FFI; addr: {:p} ({}i64, mapped: {ptr:p})
1089                     serialized: {serialized:?}
1090                     value: {value:?}",
1091                    self.ptr as *mut u8,
1092                    self.ptr
1093                );
1094            }
1095            value
1096        }
1097    }
1098
1099    impl From<Result<Vec<OutboundDelegateMsg>, DelegateError>> for DelegateInterfaceResult {
1100        fn from(value: Result<Vec<OutboundDelegateMsg>, DelegateError>) -> Self {
1101            let serialized = bincode::serialize(&value).unwrap();
1102            let size = serialized.len() as _;
1103            let ptr = serialized.as_ptr();
1104            #[cfg(feature = "trace")]
1105            {
1106                tracing::trace!(
1107                    "sending result through FFI; addr: {ptr:p} ({}),\n  serialized: {serialized:?}\n  value: {value:?}",
1108                    ptr as i64
1109                );
1110            }
1111            std::mem::forget(serialized);
1112            Self {
1113                ptr: ptr as i64,
1114                size,
1115            }
1116        }
1117    }
1118}