freenet_stdlib/client_api/
client_events.rs

1use flatbuffers::WIPOffset;
2use std::borrow::Cow;
3use std::fmt::Display;
4use std::net::SocketAddr;
5
6use serde::{de::DeserializeOwned, Deserialize, Serialize};
7
8use crate::client_api::TryFromFbs;
9use crate::generated::client_request::{
10    root_as_client_request, ClientRequestType, ContractRequest as FbsContractRequest,
11    ContractRequestType, DelegateRequest as FbsDelegateRequest, DelegateRequestType,
12};
13
14use crate::delegate_interface::DelegateContext;
15use crate::generated::common::{
16    ApplicationMessage as FbsApplicationMessage, ApplicationMessageArgs, ContractCode,
17    ContractCodeArgs, ContractContainer as FbsContractContainer, ContractContainerArgs,
18    ContractInstanceId, ContractInstanceIdArgs, ContractKey as FbsContractKey, ContractKeyArgs,
19    ContractType, DeltaUpdate, DeltaUpdateArgs, GetSecretRequest as FbsGetSecretRequest,
20    GetSecretRequestArgs, GetSecretResponse as FbsGetSecretResponse, GetSecretResponseArgs,
21    RelatedDeltaUpdate, RelatedDeltaUpdateArgs, RelatedStateAndDeltaUpdate,
22    RelatedStateAndDeltaUpdateArgs, RelatedStateUpdate, RelatedStateUpdateArgs,
23    SecretsId as FbsSecretsId, SecretsIdArgs, StateAndDeltaUpdate, StateAndDeltaUpdateArgs,
24    StateUpdate, StateUpdateArgs, UpdateData as FbsUpdateData, UpdateDataArgs, UpdateDataType,
25    WasmContractV1, WasmContractV1Args,
26};
27use crate::generated::host_response::{
28    finish_host_response_buffer, ClientResponse as FbsClientResponse, ClientResponseArgs,
29    ContextUpdated as FbsContextUpdated, ContextUpdatedArgs,
30    ContractResponse as FbsContractResponse, ContractResponseArgs, ContractResponseType,
31    DelegateKey as FbsDelegateKey, DelegateKeyArgs, DelegateResponse as FbsDelegateResponse,
32    DelegateResponseArgs, GetResponse as FbsGetResponse, GetResponseArgs,
33    HostResponse as FbsHostResponse, HostResponseArgs, HostResponseType, Ok as FbsOk, OkArgs,
34    OutboundDelegateMsg as FbsOutboundDelegateMsg, OutboundDelegateMsgArgs,
35    OutboundDelegateMsgType, PutResponse as FbsPutResponse, PutResponseArgs,
36    RequestUserInput as FbsRequestUserInput, RequestUserInputArgs,
37    SetSecretRequest as FbsSetSecretRequest, SetSecretRequestArgs,
38    UpdateNotification as FbsUpdateNotification, UpdateNotificationArgs,
39    UpdateResponse as FbsUpdateResponse, UpdateResponseArgs,
40};
41use crate::prelude::ContractContainer::Wasm;
42use crate::prelude::ContractWasmAPIVersion::V1;
43use crate::prelude::UpdateData::{
44    Delta, RelatedDelta, RelatedState, RelatedStateAndDelta, State, StateAndDelta,
45};
46use crate::{
47    delegate_interface::{DelegateKey, InboundDelegateMsg, OutboundDelegateMsg},
48    prelude::{
49        ContractKey, DelegateContainer, GetSecretRequest, Parameters, RelatedContracts, SecretsId,
50        StateSummary, UpdateData, WrappedState,
51    },
52    versioning::ContractContainer,
53};
54
55use super::WsApiError;
56
57#[derive(Debug, Serialize, Deserialize)]
58pub struct ClientError {
59    kind: Box<ErrorKind>,
60}
61
62impl ClientError {
63    pub fn into_fbs_bytes(self) -> Result<Vec<u8>, Box<ClientError>> {
64        use crate::generated::host_response::{Error, ErrorArgs};
65        let mut builder = flatbuffers::FlatBufferBuilder::new();
66        let msg_offset = builder.create_string(&self.to_string());
67        let err_offset = Error::create(
68            &mut builder,
69            &ErrorArgs {
70                msg: Some(msg_offset),
71            },
72        );
73        let host_response_offset = FbsHostResponse::create(
74            &mut builder,
75            &HostResponseArgs {
76                response_type: HostResponseType::Ok,
77                response: Some(err_offset.as_union_value()),
78            },
79        );
80        finish_host_response_buffer(&mut builder, host_response_offset);
81        Ok(builder.finished_data().to_vec())
82    }
83
84    pub fn kind(&self) -> &ErrorKind {
85        &self.kind
86    }
87}
88
89impl From<ErrorKind> for ClientError {
90    fn from(kind: ErrorKind) -> Self {
91        ClientError {
92            kind: Box::new(kind),
93        }
94    }
95}
96
97impl<T: Into<Cow<'static, str>>> From<T> for ClientError {
98    fn from(cause: T) -> Self {
99        ClientError {
100            kind: Box::new(ErrorKind::Unhandled {
101                cause: cause.into(),
102            }),
103        }
104    }
105}
106
107#[derive(thiserror::Error, Debug, Serialize, Deserialize, Clone)]
108#[non_exhaustive]
109pub enum ErrorKind {
110    #[error("comm channel between client/host closed")]
111    ChannelClosed,
112    #[error("error while deserializing: {cause}")]
113    DeserializationError { cause: Cow<'static, str> },
114    #[error("client disconnected")]
115    Disconnect,
116    #[error("failed while trying to unpack state for {0}")]
117    IncorrectState(ContractKey),
118    #[error("node not available")]
119    NodeUnavailable,
120    #[error("lost the connection with the protocol handling connections")]
121    TransportProtocolDisconnect,
122    #[error("unhandled error: {cause}")]
123    Unhandled { cause: Cow<'static, str> },
124    #[error("unknown client id: {0}")]
125    UnknownClient(usize),
126    #[error(transparent)]
127    RequestError(#[from] RequestError),
128    #[error("error while executing operation in the network: {cause}")]
129    OperationError { cause: Cow<'static, str> },
130    // TODO: identify requests by some id so we can inform clients which one failed exactly
131    #[error("operation timed out")]
132    FailedOperation,
133    #[error("peer should shutdown")]
134    Shutdown,
135}
136
137impl Display for ClientError {
138    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
139        write!(f, "client error: {}", self.kind)
140    }
141}
142
143impl std::error::Error for ClientError {}
144
145#[derive(Debug, thiserror::Error, Serialize, Deserialize, Clone)]
146#[non_exhaustive]
147pub enum RequestError {
148    #[error(transparent)]
149    ContractError(#[from] ContractError),
150    #[error(transparent)]
151    DelegateError(#[from] DelegateError),
152    #[error("client disconnect")]
153    Disconnect,
154    #[error("operation timed out")]
155    Timeout,
156}
157
158/// Errors that may happen while interacting with delegates.
159#[derive(Debug, thiserror::Error, Serialize, Deserialize, Clone)]
160#[non_exhaustive]
161pub enum DelegateError {
162    #[error("error while registering delegate {0}")]
163    RegisterError(DelegateKey),
164    #[error("execution error, cause {0}")]
165    ExecutionError(Cow<'static, str>),
166    #[error("missing delegate {0}")]
167    Missing(DelegateKey),
168    #[error("missing secret `{secret}` for delegate {key}")]
169    MissingSecret { key: DelegateKey, secret: SecretsId },
170    #[error("forbidden access to secret: {0}")]
171    ForbiddenSecretAccess(SecretsId),
172}
173
174/// Errors that may happen while interacting with contracts.
175#[derive(Debug, thiserror::Error, Serialize, Deserialize, Clone)]
176#[non_exhaustive]
177pub enum ContractError {
178    #[error("failed to get contract {key}, reason: {cause}")]
179    Get {
180        key: ContractKey,
181        cause: Cow<'static, str>,
182    },
183    #[error("put error for contract {key}, reason: {cause}")]
184    Put {
185        key: ContractKey,
186        cause: Cow<'static, str>,
187    },
188    #[error("update error for contract {key}, reason: {cause}")]
189    Update {
190        key: ContractKey,
191        cause: Cow<'static, str>,
192    },
193    #[error("failed to subscribe for contract {key}, reason: {cause}")]
194    Subscribe {
195        key: ContractKey,
196        cause: Cow<'static, str>,
197    },
198    // todo: actually build a stack of the involved keys
199    #[error("dependency contract stack overflow : {key}")]
200    ContractStackOverflow {
201        key: crate::contract_interface::ContractInstanceId,
202    },
203    #[error("missing related contract: {key}")]
204    MissingRelated {
205        key: crate::contract_interface::ContractInstanceId,
206    },
207    #[error("missing contract: {key}")]
208    MissingContract {
209        key: crate::contract_interface::ContractInstanceId,
210    },
211}
212
213impl ContractError {
214    const EXECUTION_ERROR: &'static str = "execution error";
215    const INVALID_PUT: &'static str = "invalid put";
216
217    pub fn update_exec_error(key: ContractKey, additional_info: impl std::fmt::Display) -> Self {
218        Self::Update {
219            key,
220            cause: format!(
221                "{exec_err}: {additional_info}",
222                exec_err = Self::EXECUTION_ERROR
223            )
224            .into(),
225        }
226    }
227
228    pub fn invalid_put(key: ContractKey) -> Self {
229        Self::Put {
230            key,
231            cause: Self::INVALID_PUT.into(),
232        }
233    }
234
235    pub fn invalid_update(key: ContractKey) -> Self {
236        Self::Update {
237            key,
238            cause: Self::INVALID_PUT.into(),
239        }
240    }
241}
242
243/// A request from a client application to the host.
244#[derive(Serialize, Deserialize, Debug, Clone)]
245#[non_exhaustive]
246// #[cfg_attr(test, derive(arbitrary::Arbitrary))]
247pub enum ClientRequest<'a> {
248    DelegateOp(#[serde(borrow)] DelegateRequest<'a>),
249    ContractOp(#[serde(borrow)] ContractRequest<'a>),
250    Disconnect {
251        cause: Option<Cow<'static, str>>,
252    },
253    Authenticate {
254        token: String,
255    },
256    NodeQueries(ConnectedPeers),
257    /// Gracefully disconnect from the host.
258    Close,
259}
260
261#[derive(Serialize, Deserialize, Debug, Clone)]
262pub struct ConnectedPeers {}
263
264impl ClientRequest<'_> {
265    pub fn into_owned(self) -> ClientRequest<'static> {
266        match self {
267            ClientRequest::ContractOp(op) => {
268                let owned = match op {
269                    ContractRequest::Put {
270                        contract,
271                        state,
272                        related_contracts,
273                        subscribe,
274                    } => {
275                        let related_contracts = related_contracts.into_owned();
276                        ContractRequest::Put {
277                            contract,
278                            state,
279                            related_contracts,
280                            subscribe,
281                        }
282                    }
283                    ContractRequest::Update { key, data } => {
284                        let data = data.into_owned();
285                        ContractRequest::Update { key, data }
286                    }
287                    ContractRequest::Get {
288                        key,
289                        return_contract_code,
290                        subscribe,
291                    } => ContractRequest::Get {
292                        key,
293                        return_contract_code,
294                        subscribe,
295                    },
296                    ContractRequest::Subscribe { key, summary } => ContractRequest::Subscribe {
297                        key,
298                        summary: summary.map(StateSummary::into_owned),
299                    },
300                };
301                owned.into()
302            }
303            ClientRequest::DelegateOp(op) => {
304                let op = op.into_owned();
305                ClientRequest::DelegateOp(op)
306            }
307            ClientRequest::Disconnect { cause } => ClientRequest::Disconnect { cause },
308            ClientRequest::Authenticate { token } => ClientRequest::Authenticate { token },
309            ClientRequest::NodeQueries(query) => ClientRequest::NodeQueries(query),
310            ClientRequest::Close => ClientRequest::Close,
311        }
312    }
313
314    pub fn is_disconnect(&self) -> bool {
315        matches!(self, Self::Disconnect { .. })
316    }
317
318    pub fn try_decode_fbs(msg: &[u8]) -> Result<ClientRequest, WsApiError> {
319        let req = {
320            match root_as_client_request(msg) {
321                Ok(client_request) => match client_request.client_request_type() {
322                    ClientRequestType::ContractRequest => {
323                        let contract_request =
324                            client_request.client_request_as_contract_request().unwrap();
325                        ContractRequest::try_decode_fbs(&contract_request)?.into()
326                    }
327                    ClientRequestType::DelegateRequest => {
328                        let delegate_request =
329                            client_request.client_request_as_delegate_request().unwrap();
330                        DelegateRequest::try_decode_fbs(&delegate_request)?.into()
331                    }
332                    ClientRequestType::Disconnect => {
333                        let delegate_request =
334                            client_request.client_request_as_disconnect().unwrap();
335                        let cause = delegate_request
336                            .cause()
337                            .map(|cause_msg| cause_msg.to_string().into());
338                        ClientRequest::Disconnect { cause }
339                    }
340                    ClientRequestType::Authenticate => {
341                        let auth_req = client_request.client_request_as_authenticate().unwrap();
342                        let token = auth_req.token();
343                        ClientRequest::Authenticate {
344                            token: token.to_owned(),
345                        }
346                    }
347                    _ => unreachable!(),
348                },
349                Err(e) => {
350                    let cause = format!("{e}");
351                    return Err(WsApiError::deserialization(cause));
352                }
353            }
354        };
355
356        Ok(req)
357    }
358}
359
360#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
361#[non_exhaustive]
362pub enum ContractRequest<'a> {
363    /// Insert a new value in a contract corresponding with the provided key.
364    Put {
365        contract: ContractContainer,
366        /// Value to upsert in the contract.
367        state: WrappedState,
368        /// Related contracts.
369        #[serde(borrow)]
370        related_contracts: RelatedContracts<'a>,
371        /// If this flag is set then subscribe to updates for this contract.
372        subscribe: bool,
373    },
374    /// Update an existing contract corresponding with the provided key.
375    Update {
376        key: ContractKey,
377        #[serde(borrow)]
378        data: UpdateData<'a>,
379    },
380    /// Fetch the current state from a contract corresponding to the provided key.
381    Get {
382        /// Key of the contract.
383        key: ContractKey,
384        /// If this flag is set then fetch also the contract itself.
385        return_contract_code: bool,
386        /// If this flag is set then subscribe to updates for this contract.
387        subscribe: bool,
388    },
389    /// Subscribe to the changes in a given contract. Implicitly starts a get operation
390    /// if the contract is not present yet.
391    Subscribe {
392        key: ContractKey,
393        summary: Option<StateSummary<'a>>,
394    },
395}
396
397impl ContractRequest<'_> {
398    pub fn into_owned(self) -> ContractRequest<'static> {
399        match self {
400            Self::Put {
401                contract,
402                state,
403                related_contracts,
404                subscribe,
405            } => ContractRequest::Put {
406                contract,
407                state,
408                related_contracts: related_contracts.into_owned(),
409                subscribe,
410            },
411            Self::Update { key, data } => ContractRequest::Update {
412                key,
413                data: data.into_owned(),
414            },
415            Self::Get {
416                key,
417                return_contract_code: fetch_contract,
418                subscribe,
419            } => ContractRequest::Get {
420                key,
421                return_contract_code: fetch_contract,
422                subscribe,
423            },
424            Self::Subscribe { key, summary } => ContractRequest::Subscribe {
425                key,
426                summary: summary.map(StateSummary::into_owned),
427            },
428        }
429    }
430}
431
432impl<'a> From<ContractRequest<'a>> for ClientRequest<'a> {
433    fn from(op: ContractRequest<'a>) -> Self {
434        ClientRequest::ContractOp(op)
435    }
436}
437
438/// Deserializes a `ContractRequest` from a Flatbuffers message.
439impl<'a> TryFromFbs<&FbsContractRequest<'a>> for ContractRequest<'a> {
440    fn try_decode_fbs(request: &FbsContractRequest<'a>) -> Result<Self, WsApiError> {
441        let req = {
442            match request.contract_request_type() {
443                ContractRequestType::Get => {
444                    let get = request.contract_request_as_get().unwrap();
445                    let key = ContractKey::try_decode_fbs(&get.key())?;
446                    let fetch_contract = get.fetch_contract();
447                    let subscribe = get.subscribe();
448                    ContractRequest::Get {
449                        key,
450                        return_contract_code: fetch_contract,
451                        subscribe,
452                    }
453                }
454                ContractRequestType::Put => {
455                    let put = request.contract_request_as_put().unwrap();
456                    let contract = ContractContainer::try_decode_fbs(&put.container())?;
457                    let state = WrappedState::new(put.wrapped_state().bytes().to_vec());
458                    let related_contracts =
459                        RelatedContracts::try_decode_fbs(&put.related_contracts())?.into_owned();
460                    let subscribe = put.subscribe();
461                    ContractRequest::Put {
462                        contract,
463                        state,
464                        related_contracts,
465                        subscribe,
466                    }
467                }
468                ContractRequestType::Update => {
469                    let update = request.contract_request_as_update().unwrap();
470                    let key = ContractKey::try_decode_fbs(&update.key())?;
471                    let data = UpdateData::try_decode_fbs(&update.data())?.into_owned();
472                    ContractRequest::Update { key, data }
473                }
474                ContractRequestType::Subscribe => {
475                    let subscribe = request.contract_request_as_subscribe().unwrap();
476                    let key = ContractKey::try_decode_fbs(&subscribe.key())?;
477                    let summary = subscribe
478                        .summary()
479                        .map(|summary_data| StateSummary::from(summary_data.bytes()));
480                    ContractRequest::Subscribe { key, summary }
481                }
482                _ => unreachable!(),
483            }
484        };
485
486        Ok(req)
487    }
488}
489
490impl<'a> From<DelegateRequest<'a>> for ClientRequest<'a> {
491    fn from(op: DelegateRequest<'a>) -> Self {
492        ClientRequest::DelegateOp(op)
493    }
494}
495
496#[derive(Serialize, Deserialize, Debug, Clone)]
497#[non_exhaustive]
498pub enum DelegateRequest<'a> {
499    ApplicationMessages {
500        key: DelegateKey,
501        #[serde(deserialize_with = "Parameters::deser_params")]
502        params: Parameters<'a>,
503        #[serde(borrow)]
504        inbound: Vec<InboundDelegateMsg<'a>>,
505    },
506    GetSecretRequest {
507        key: DelegateKey,
508        #[serde(borrow)]
509        params: Parameters<'a>,
510        get_request: GetSecretRequest,
511    },
512    RegisterDelegate {
513        delegate: DelegateContainer,
514        cipher: [u8; 32],
515        nonce: [u8; 24],
516    },
517    UnregisterDelegate(DelegateKey),
518}
519
520impl DelegateRequest<'_> {
521    pub const DEFAULT_CIPHER: [u8; 32] = [
522        0, 24, 22, 150, 112, 207, 24, 65, 182, 161, 169, 227, 66, 182, 237, 215, 206, 164, 58, 161,
523        64, 108, 157, 195, 0, 0, 0, 0, 0, 0, 0, 0,
524    ];
525
526    pub const DEFAULT_NONCE: [u8; 24] = [
527        57, 18, 79, 116, 63, 134, 93, 39, 208, 161, 156, 229, 222, 247, 111, 79, 210, 126, 127, 55,
528        224, 150, 139, 80,
529    ];
530
531    pub fn into_owned(self) -> DelegateRequest<'static> {
532        match self {
533            DelegateRequest::ApplicationMessages {
534                key,
535                inbound,
536                params,
537            } => DelegateRequest::ApplicationMessages {
538                key,
539                params: params.into_owned(),
540                inbound: inbound.into_iter().map(|e| e.into_owned()).collect(),
541            },
542            DelegateRequest::GetSecretRequest {
543                key,
544                get_request,
545                params,
546            } => DelegateRequest::GetSecretRequest {
547                key,
548                get_request,
549                params: params.into_owned(),
550            },
551            DelegateRequest::RegisterDelegate {
552                delegate,
553                cipher,
554                nonce,
555            } => DelegateRequest::RegisterDelegate {
556                delegate,
557                cipher,
558                nonce,
559            },
560            DelegateRequest::UnregisterDelegate(key) => DelegateRequest::UnregisterDelegate(key),
561        }
562    }
563
564    pub fn key(&self) -> &DelegateKey {
565        match self {
566            DelegateRequest::ApplicationMessages { key, .. } => key,
567            DelegateRequest::GetSecretRequest { key, .. } => key,
568            DelegateRequest::RegisterDelegate { delegate, .. } => delegate.key(),
569            DelegateRequest::UnregisterDelegate(key) => key,
570        }
571    }
572}
573
574impl Display for ClientRequest<'_> {
575    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
576        match self {
577            ClientRequest::ContractOp(op) => match op {
578                ContractRequest::Put {
579                    contract, state, ..
580                } => {
581                    write!(
582                        f,
583                        "ContractRequest::Put for contract `{contract}` with state {state}"
584                    )
585                }
586                ContractRequest::Update { key, .. } => write!(f, "update request for {key}"),
587                ContractRequest::Get {
588                    key,
589                    return_contract_code: contract,
590                    ..
591                } => {
592                    write!(
593                        f,
594                        "ContractRequest::Get for key `{key}` (fetch full contract: {contract})"
595                    )
596                }
597                ContractRequest::Subscribe { key, .. } => {
598                    write!(f, "ContractRequest::Subscribe for `{key}`")
599                }
600            },
601            ClientRequest::DelegateOp(op) => {
602                match op {
603                    DelegateRequest::ApplicationMessages { key, inbound, .. } => {
604                        write!(
605                            f,
606                            "DelegateRequest::ApplicationMessages for `{key}` with {} messages",
607                            inbound.len()
608                        )
609                    }
610                    DelegateRequest::GetSecretRequest {
611                        get_request: GetSecretRequest { key: secret_id, .. },
612                        key,
613                        ..
614                    } => {
615                        write!(f, "DelegateRequest::GetSecretRequest secret_id `{secret_id}` for key `{key}`")
616                    }
617                    DelegateRequest::RegisterDelegate { delegate, .. } => {
618                        write!(
619                            f,
620                            "DelegateRequest::RegisterDelegate for delegate.key()=`{}`",
621                            delegate.key()
622                        )
623                    }
624                    DelegateRequest::UnregisterDelegate(key) => {
625                        write!(f, "DelegateRequest::UnregisterDelegate for key `{key}`")
626                    }
627                }
628            }
629            ClientRequest::Disconnect { .. } => write!(f, "client disconnected"),
630            ClientRequest::Authenticate { .. } => write!(f, "authenticate"),
631            ClientRequest::NodeQueries(query) => write!(f, "node queries: {:?}", query),
632            ClientRequest::Close => write!(f, "close"),
633        }
634    }
635}
636
637/// Deserializes a `DelegateRequest` from a Flatbuffers message.
638impl<'a> TryFromFbs<&FbsDelegateRequest<'a>> for DelegateRequest<'a> {
639    fn try_decode_fbs(request: &FbsDelegateRequest<'a>) -> Result<Self, WsApiError> {
640        let req = {
641            match request.delegate_request_type() {
642                DelegateRequestType::ApplicationMessages => {
643                    let app_msg = request.delegate_request_as_application_messages().unwrap();
644                    let key = DelegateKey::try_decode_fbs(&app_msg.key())?;
645                    let params = Parameters::from(app_msg.params().bytes());
646                    let inbound = app_msg
647                        .inbound()
648                        .iter()
649                        .map(|msg| InboundDelegateMsg::try_decode_fbs(&msg))
650                        .collect::<Result<Vec<_>, _>>()?;
651                    DelegateRequest::ApplicationMessages {
652                        key,
653                        params,
654                        inbound,
655                    }
656                }
657                DelegateRequestType::GetSecretRequestType => {
658                    let get_secret = request
659                        .delegate_request_as_get_secret_request_type()
660                        .unwrap();
661                    let key = DelegateKey::try_decode_fbs(&get_secret.key())?;
662                    let params = Parameters::from(get_secret.params().bytes().to_vec());
663                    let get_request = GetSecretRequest {
664                        key: SecretsId::try_decode_fbs(&get_secret.get_request().key())?,
665                        context: DelegateContext::new(
666                            get_secret.get_request().delegate_context().bytes().to_vec(),
667                        ),
668                        processed: get_secret.get_request().processed(),
669                    };
670                    DelegateRequest::GetSecretRequest {
671                        key,
672                        params,
673                        get_request,
674                    }
675                }
676                DelegateRequestType::RegisterDelegate => {
677                    let register = request.delegate_request_as_register_delegate().unwrap();
678                    let delegate = DelegateContainer::try_decode_fbs(&register.delegate())?;
679                    let cipher =
680                        <[u8; 32]>::try_from(register.cipher().bytes().to_vec().as_slice())
681                            .unwrap();
682                    let nonce =
683                        <[u8; 24]>::try_from(register.nonce().bytes().to_vec().as_slice()).unwrap();
684                    DelegateRequest::RegisterDelegate {
685                        delegate,
686                        cipher,
687                        nonce,
688                    }
689                }
690                DelegateRequestType::UnregisterDelegate => {
691                    let unregister = request.delegate_request_as_unregister_delegate().unwrap();
692                    let key = DelegateKey::try_decode_fbs(&unregister.key())?;
693                    DelegateRequest::UnregisterDelegate(key)
694                }
695                _ => unreachable!(),
696            }
697        };
698
699        Ok(req)
700    }
701}
702
703/// A response to a previous [`ClientRequest`]
704#[derive(Serialize, Deserialize, Debug)]
705#[non_exhaustive]
706pub enum HostResponse<T = WrappedState> {
707    ContractResponse(#[serde(bound(deserialize = "T: DeserializeOwned"))] ContractResponse<T>),
708    DelegateResponse {
709        key: DelegateKey,
710        values: Vec<OutboundDelegateMsg>,
711    },
712    QueryResponse(QueryResponse),
713    /// A requested action which doesn't require an answer was performed successfully.
714    Ok,
715}
716
717type Peer = String;
718
719#[derive(Serialize, Deserialize, Debug)]
720pub enum QueryResponse {
721    ConnectedPeers { peers: Vec<(Peer, SocketAddr)> },
722}
723
724impl HostResponse {
725    pub fn unwrap_put(self) -> ContractKey {
726        if let Self::ContractResponse(ContractResponse::PutResponse { key }) = self {
727            key
728        } else {
729            panic!("called `HostResponse::unwrap_put()` on other than `PutResponse` value")
730        }
731    }
732
733    pub fn unwrap_get(self) -> (WrappedState, Option<ContractContainer>) {
734        if let Self::ContractResponse(ContractResponse::GetResponse {
735            contract, state, ..
736        }) = self
737        {
738            (state, contract)
739        } else {
740            panic!("called `HostResponse::unwrap_put()` on other than `PutResponse` value")
741        }
742    }
743
744    pub fn into_fbs_bytes(self) -> Result<Vec<u8>, Box<ClientError>> {
745        let mut builder = flatbuffers::FlatBufferBuilder::new();
746        match self {
747            HostResponse::ContractResponse(res) => match res {
748                ContractResponse::PutResponse { key } => {
749                    let instance_data = builder.create_vector(key.as_bytes());
750                    let instance_offset = ContractInstanceId::create(
751                        &mut builder,
752                        &ContractInstanceIdArgs {
753                            data: Some(instance_data),
754                        },
755                    );
756
757                    let code = key
758                        .code_hash()
759                        .map(|code| builder.create_vector(code.0.as_ref()));
760                    let key_offset = FbsContractKey::create(
761                        &mut builder,
762                        &ContractKeyArgs {
763                            instance: Some(instance_offset),
764                            code,
765                        },
766                    );
767
768                    let put_offset = FbsPutResponse::create(
769                        &mut builder,
770                        &PutResponseArgs {
771                            key: Some(key_offset),
772                        },
773                    );
774
775                    let contract_response_offset = FbsContractResponse::create(
776                        &mut builder,
777                        &ContractResponseArgs {
778                            contract_response: Some(put_offset.as_union_value()),
779                            contract_response_type: ContractResponseType::PutResponse,
780                        },
781                    );
782
783                    let response_offset = FbsHostResponse::create(
784                        &mut builder,
785                        &HostResponseArgs {
786                            response: Some(contract_response_offset.as_union_value()),
787                            response_type: HostResponseType::ContractResponse,
788                        },
789                    );
790
791                    finish_host_response_buffer(&mut builder, response_offset);
792                    Ok(builder.finished_data().to_vec())
793                }
794                ContractResponse::UpdateResponse { key, summary } => {
795                    let instance_data = builder.create_vector(key.as_bytes());
796                    let instance_offset = ContractInstanceId::create(
797                        &mut builder,
798                        &ContractInstanceIdArgs {
799                            data: Some(instance_data),
800                        },
801                    );
802
803                    let code = key
804                        .code_hash()
805                        .map(|code| builder.create_vector(code.0.as_ref()));
806
807                    let key_offset = FbsContractKey::create(
808                        &mut builder,
809                        &ContractKeyArgs {
810                            instance: Some(instance_offset),
811                            code,
812                        },
813                    );
814
815                    let summary_data = builder.create_vector(&summary.into_bytes());
816
817                    let update_response_offset = FbsUpdateResponse::create(
818                        &mut builder,
819                        &UpdateResponseArgs {
820                            key: Some(key_offset),
821                            summary: Some(summary_data),
822                        },
823                    );
824
825                    let contract_response_offset = FbsContractResponse::create(
826                        &mut builder,
827                        &ContractResponseArgs {
828                            contract_response: Some(update_response_offset.as_union_value()),
829                            contract_response_type: ContractResponseType::UpdateResponse,
830                        },
831                    );
832
833                    let response_offset = FbsHostResponse::create(
834                        &mut builder,
835                        &HostResponseArgs {
836                            response: Some(contract_response_offset.as_union_value()),
837                            response_type: HostResponseType::ContractResponse,
838                        },
839                    );
840
841                    finish_host_response_buffer(&mut builder, response_offset);
842                    Ok(builder.finished_data().to_vec())
843                }
844                ContractResponse::GetResponse {
845                    key,
846                    contract: contract_container,
847                    state,
848                } => {
849                    let instance_data = builder.create_vector(key.as_bytes());
850                    let instance_offset = ContractInstanceId::create(
851                        &mut builder,
852                        &ContractInstanceIdArgs {
853                            data: Some(instance_data),
854                        },
855                    );
856
857                    let code = key.code_hash().map(|code| builder.create_vector(&code.0));
858                    let key_offset = FbsContractKey::create(
859                        &mut builder,
860                        &ContractKeyArgs {
861                            instance: Some(instance_offset),
862                            code,
863                        },
864                    );
865
866                    let container_offset = if let Some(contract) = contract_container {
867                        let data = builder.create_vector(contract.key().as_bytes());
868
869                        let instance_offset = ContractInstanceId::create(
870                            &mut builder,
871                            &ContractInstanceIdArgs { data: Some(data) },
872                        );
873
874                        let code = contract
875                            .key()
876                            .code_hash()
877                            .map(|code| builder.create_vector(&code.0));
878                        let contract_key_offset = FbsContractKey::create(
879                            &mut builder,
880                            &ContractKeyArgs {
881                                instance: Some(instance_offset),
882                                code,
883                            },
884                        );
885
886                        let contract_data =
887                            builder.create_vector(contract.clone().unwrap_v1().data.data());
888                        let contract_code_hash =
889                            builder.create_vector(&contract.clone().unwrap_v1().data.hash().0);
890
891                        let contract_code_offset = ContractCode::create(
892                            &mut builder,
893                            &ContractCodeArgs {
894                                data: Some(contract_data),
895                                code_hash: Some(contract_code_hash),
896                            },
897                        );
898
899                        let contract_params =
900                            builder.create_vector(&contract.clone().params().into_bytes());
901
902                        let contract_offset = match contract {
903                            Wasm(V1(..)) => WasmContractV1::create(
904                                &mut builder,
905                                &WasmContractV1Args {
906                                    key: Some(contract_key_offset),
907                                    data: Some(contract_code_offset),
908                                    parameters: Some(contract_params),
909                                },
910                            ),
911                        };
912
913                        Some(FbsContractContainer::create(
914                            &mut builder,
915                            &ContractContainerArgs {
916                                contract_type: ContractType::WasmContractV1,
917                                contract: Some(contract_offset.as_union_value()),
918                            },
919                        ))
920                    } else {
921                        None
922                    };
923
924                    let state_data = builder.create_vector(&state);
925
926                    let get_offset = FbsGetResponse::create(
927                        &mut builder,
928                        &GetResponseArgs {
929                            key: Some(key_offset),
930                            contract: container_offset,
931                            state: Some(state_data),
932                        },
933                    );
934
935                    let contract_response_offset = FbsContractResponse::create(
936                        &mut builder,
937                        &ContractResponseArgs {
938                            contract_response_type: ContractResponseType::GetResponse,
939                            contract_response: Some(get_offset.as_union_value()),
940                        },
941                    );
942
943                    let response_offset = FbsHostResponse::create(
944                        &mut builder,
945                        &HostResponseArgs {
946                            response: Some(contract_response_offset.as_union_value()),
947                            response_type: HostResponseType::ContractResponse,
948                        },
949                    );
950
951                    finish_host_response_buffer(&mut builder, response_offset);
952                    Ok(builder.finished_data().to_vec())
953                }
954                ContractResponse::UpdateNotification { key, update } => {
955                    let instance_data = builder.create_vector(key.as_bytes());
956                    let instance_offset = ContractInstanceId::create(
957                        &mut builder,
958                        &ContractInstanceIdArgs {
959                            data: Some(instance_data),
960                        },
961                    );
962
963                    let code = key
964                        .code_hash()
965                        .map(|code| builder.create_vector(code.0.as_ref()));
966                    let key_offset = FbsContractKey::create(
967                        &mut builder,
968                        &ContractKeyArgs {
969                            instance: Some(instance_offset),
970                            code,
971                        },
972                    );
973
974                    let update_data = match update {
975                        State(state) => {
976                            let state_data = builder.create_vector(&state.into_bytes());
977                            let state_update_offset = StateUpdate::create(
978                                &mut builder,
979                                &StateUpdateArgs {
980                                    state: Some(state_data),
981                                },
982                            );
983                            FbsUpdateData::create(
984                                &mut builder,
985                                &UpdateDataArgs {
986                                    update_data_type: UpdateDataType::StateUpdate,
987                                    update_data: Some(state_update_offset.as_union_value()),
988                                },
989                            )
990                        }
991                        Delta(delta) => {
992                            let delta_data = builder.create_vector(&delta.into_bytes());
993                            let update_offset = DeltaUpdate::create(
994                                &mut builder,
995                                &DeltaUpdateArgs {
996                                    delta: Some(delta_data),
997                                },
998                            );
999                            FbsUpdateData::create(
1000                                &mut builder,
1001                                &UpdateDataArgs {
1002                                    update_data_type: UpdateDataType::DeltaUpdate,
1003                                    update_data: Some(update_offset.as_union_value()),
1004                                },
1005                            )
1006                        }
1007                        StateAndDelta { state, delta } => {
1008                            let state_data = builder.create_vector(&state.into_bytes());
1009                            let delta_data = builder.create_vector(&delta.into_bytes());
1010
1011                            let update_offset = StateAndDeltaUpdate::create(
1012                                &mut builder,
1013                                &StateAndDeltaUpdateArgs {
1014                                    state: Some(state_data),
1015                                    delta: Some(delta_data),
1016                                },
1017                            );
1018
1019                            FbsUpdateData::create(
1020                                &mut builder,
1021                                &UpdateDataArgs {
1022                                    update_data_type: UpdateDataType::StateAndDeltaUpdate,
1023                                    update_data: Some(update_offset.as_union_value()),
1024                                },
1025                            )
1026                        }
1027                        RelatedState { related_to, state } => {
1028                            let state_data = builder.create_vector(&state.into_bytes());
1029                            let instance_data =
1030                                builder.create_vector(related_to.encode().as_bytes());
1031
1032                            let instance_offset = ContractInstanceId::create(
1033                                &mut builder,
1034                                &ContractInstanceIdArgs {
1035                                    data: Some(instance_data),
1036                                },
1037                            );
1038
1039                            let update_offset = RelatedStateUpdate::create(
1040                                &mut builder,
1041                                &RelatedStateUpdateArgs {
1042                                    related_to: Some(instance_offset),
1043                                    state: Some(state_data),
1044                                },
1045                            );
1046
1047                            FbsUpdateData::create(
1048                                &mut builder,
1049                                &UpdateDataArgs {
1050                                    update_data_type: UpdateDataType::RelatedStateUpdate,
1051                                    update_data: Some(update_offset.as_union_value()),
1052                                },
1053                            )
1054                        }
1055                        RelatedDelta { related_to, delta } => {
1056                            let instance_data =
1057                                builder.create_vector(related_to.encode().as_bytes());
1058                            let delta_data = builder.create_vector(&delta.into_bytes());
1059
1060                            let instance_offset = ContractInstanceId::create(
1061                                &mut builder,
1062                                &ContractInstanceIdArgs {
1063                                    data: Some(instance_data),
1064                                },
1065                            );
1066
1067                            let update_offset = RelatedDeltaUpdate::create(
1068                                &mut builder,
1069                                &RelatedDeltaUpdateArgs {
1070                                    related_to: Some(instance_offset),
1071                                    delta: Some(delta_data),
1072                                },
1073                            );
1074
1075                            FbsUpdateData::create(
1076                                &mut builder,
1077                                &UpdateDataArgs {
1078                                    update_data_type: UpdateDataType::RelatedDeltaUpdate,
1079                                    update_data: Some(update_offset.as_union_value()),
1080                                },
1081                            )
1082                        }
1083                        RelatedStateAndDelta {
1084                            related_to,
1085                            state,
1086                            delta,
1087                        } => {
1088                            let instance_data =
1089                                builder.create_vector(related_to.encode().as_bytes());
1090                            let state_data = builder.create_vector(&state.into_bytes());
1091                            let delta_data = builder.create_vector(&delta.into_bytes());
1092
1093                            let instance_offset = ContractInstanceId::create(
1094                                &mut builder,
1095                                &ContractInstanceIdArgs {
1096                                    data: Some(instance_data),
1097                                },
1098                            );
1099
1100                            let update_offset = RelatedStateAndDeltaUpdate::create(
1101                                &mut builder,
1102                                &RelatedStateAndDeltaUpdateArgs {
1103                                    related_to: Some(instance_offset),
1104                                    state: Some(state_data),
1105                                    delta: Some(delta_data),
1106                                },
1107                            );
1108
1109                            FbsUpdateData::create(
1110                                &mut builder,
1111                                &UpdateDataArgs {
1112                                    update_data_type: UpdateDataType::RelatedStateAndDeltaUpdate,
1113                                    update_data: Some(update_offset.as_union_value()),
1114                                },
1115                            )
1116                        }
1117                    };
1118
1119                    let update_notification_offset = FbsUpdateNotification::create(
1120                        &mut builder,
1121                        &UpdateNotificationArgs {
1122                            key: Some(key_offset),
1123                            update: Some(update_data),
1124                        },
1125                    );
1126
1127                    let put_response_offset = FbsContractResponse::create(
1128                        &mut builder,
1129                        &ContractResponseArgs {
1130                            contract_response_type: ContractResponseType::UpdateNotification,
1131                            contract_response: Some(update_notification_offset.as_union_value()),
1132                        },
1133                    );
1134
1135                    let host_response_offset = FbsHostResponse::create(
1136                        &mut builder,
1137                        &HostResponseArgs {
1138                            response_type: HostResponseType::ContractResponse,
1139                            response: Some(put_response_offset.as_union_value()),
1140                        },
1141                    );
1142
1143                    finish_host_response_buffer(&mut builder, host_response_offset);
1144                    Ok(builder.finished_data().to_vec())
1145                }
1146                ContractResponse::SubscribeResponse { .. } => todo!(),
1147            },
1148            HostResponse::DelegateResponse { key, values } => {
1149                let key_data = builder.create_vector(key.bytes());
1150                let code_hash_data = builder.create_vector(&key.code_hash().0);
1151                let key_offset = FbsDelegateKey::create(
1152                    &mut builder,
1153                    &DelegateKeyArgs {
1154                        key: Some(key_data),
1155                        code_hash: Some(code_hash_data),
1156                    },
1157                );
1158                let mut messages: Vec<WIPOffset<FbsOutboundDelegateMsg>> = Vec::new();
1159                values.iter().for_each(|msg| match msg {
1160                    OutboundDelegateMsg::ApplicationMessage(app) => {
1161                        let instance_data = builder.create_vector(key.bytes());
1162                        let instance_offset = ContractInstanceId::create(
1163                            &mut builder,
1164                            &ContractInstanceIdArgs {
1165                                data: Some(instance_data),
1166                            },
1167                        );
1168                        let payload_data = builder.create_vector(&app.payload);
1169                        let delegate_context_data = builder.create_vector(app.context.as_ref());
1170                        let app_offset = FbsApplicationMessage::create(
1171                            &mut builder,
1172                            &ApplicationMessageArgs {
1173                                app: Some(instance_offset),
1174                                payload: Some(payload_data),
1175                                context: Some(delegate_context_data),
1176                                processed: app.processed,
1177                            },
1178                        );
1179                        let msg = FbsOutboundDelegateMsg::create(
1180                            &mut builder,
1181                            &OutboundDelegateMsgArgs {
1182                                inbound_type: OutboundDelegateMsgType::common_ApplicationMessage,
1183                                inbound: Some(app_offset.as_union_value()),
1184                            },
1185                        );
1186                        messages.push(msg);
1187                    }
1188                    OutboundDelegateMsg::RequestUserInput(input) => {
1189                        let message_data = builder.create_vector(input.message.bytes());
1190                        let mut responses: Vec<WIPOffset<FbsClientResponse>> = Vec::new();
1191                        input.responses.iter().for_each(|resp| {
1192                            let response_data = builder.create_vector(resp.bytes());
1193                            let response = FbsClientResponse::create(
1194                                &mut builder,
1195                                &ClientResponseArgs {
1196                                    data: Some(response_data),
1197                                },
1198                            );
1199                            responses.push(response)
1200                        });
1201                        let responses_offset = builder.create_vector(&responses);
1202                        let input_offset = FbsRequestUserInput::create(
1203                            &mut builder,
1204                            &RequestUserInputArgs {
1205                                request_id: input.request_id,
1206                                message: Some(message_data),
1207                                responses: Some(responses_offset),
1208                            },
1209                        );
1210                        let msg = FbsOutboundDelegateMsg::create(
1211                            &mut builder,
1212                            &OutboundDelegateMsgArgs {
1213                                inbound_type: OutboundDelegateMsgType::RequestUserInput,
1214                                inbound: Some(input_offset.as_union_value()),
1215                            },
1216                        );
1217                        messages.push(msg);
1218                    }
1219                    OutboundDelegateMsg::ContextUpdated(context) => {
1220                        let context_data = builder.create_vector(context.as_ref());
1221                        let context_offset = FbsContextUpdated::create(
1222                            &mut builder,
1223                            &ContextUpdatedArgs {
1224                                context: Some(context_data),
1225                            },
1226                        );
1227                        let msg = FbsOutboundDelegateMsg::create(
1228                            &mut builder,
1229                            &OutboundDelegateMsgArgs {
1230                                inbound_type: OutboundDelegateMsgType::ContextUpdated,
1231                                inbound: Some(context_offset.as_union_value()),
1232                            },
1233                        );
1234                        messages.push(msg);
1235                    }
1236                    OutboundDelegateMsg::GetSecretRequest(request) => {
1237                        let secret_key_data = builder.create_vector(request.key.key());
1238                        let secret_hash_data = builder.create_vector(request.key.hash());
1239                        let secret_id_offset = FbsSecretsId::create(
1240                            &mut builder,
1241                            &SecretsIdArgs {
1242                                key: Some(secret_key_data),
1243                                hash: Some(secret_hash_data),
1244                            },
1245                        );
1246
1247                        let delegate_context_data = builder.create_vector(request.context.as_ref());
1248                        let request_offset = FbsGetSecretRequest::create(
1249                            &mut builder,
1250                            &GetSecretRequestArgs {
1251                                key: Some(secret_id_offset),
1252                                delegate_context: Some(delegate_context_data),
1253                                processed: request.processed,
1254                            },
1255                        );
1256                        let msg = FbsOutboundDelegateMsg::create(
1257                            &mut builder,
1258                            &OutboundDelegateMsgArgs {
1259                                inbound_type: OutboundDelegateMsgType::common_GetSecretRequest,
1260                                inbound: Some(request_offset.as_union_value()),
1261                            },
1262                        );
1263                        messages.push(msg);
1264                    }
1265                    OutboundDelegateMsg::SetSecretRequest(request) => {
1266                        let secret_key_data = builder.create_vector(request.key.key());
1267                        let secret_hash_data = builder.create_vector(request.key.hash());
1268                        let secret_id_offset = FbsSecretsId::create(
1269                            &mut builder,
1270                            &SecretsIdArgs {
1271                                key: Some(secret_key_data),
1272                                hash: Some(secret_hash_data),
1273                            },
1274                        );
1275
1276                        let value_data = request
1277                            .value
1278                            .clone()
1279                            .map(|value| builder.create_vector(value.as_slice()));
1280                        let request_offset = FbsSetSecretRequest::create(
1281                            &mut builder,
1282                            &SetSecretRequestArgs {
1283                                key: Some(secret_id_offset),
1284                                value: value_data,
1285                            },
1286                        );
1287                        let msg = FbsOutboundDelegateMsg::create(
1288                            &mut builder,
1289                            &OutboundDelegateMsgArgs {
1290                                inbound_type: OutboundDelegateMsgType::SetSecretRequest,
1291                                inbound: Some(request_offset.as_union_value()),
1292                            },
1293                        );
1294                        messages.push(msg);
1295                    }
1296                    OutboundDelegateMsg::GetSecretResponse(response) => {
1297                        let secret_key_data = builder.create_vector(response.key.key());
1298                        let secret_hash_data = builder.create_vector(response.key.hash());
1299                        let secret_id_offset = FbsSecretsId::create(
1300                            &mut builder,
1301                            &SecretsIdArgs {
1302                                key: Some(secret_key_data),
1303                                hash: Some(secret_hash_data),
1304                            },
1305                        );
1306
1307                        let value_data = response
1308                            .value
1309                            .clone()
1310                            .map(|value| builder.create_vector(value.as_slice()));
1311
1312                        let delegate_context_data =
1313                            builder.create_vector(response.context.as_ref());
1314                        let response_offset = FbsGetSecretResponse::create(
1315                            &mut builder,
1316                            &GetSecretResponseArgs {
1317                                key: Some(secret_id_offset),
1318                                value: value_data,
1319                                delegate_context: Some(delegate_context_data),
1320                            },
1321                        );
1322                        let msg = FbsOutboundDelegateMsg::create(
1323                            &mut builder,
1324                            &OutboundDelegateMsgArgs {
1325                                inbound_type: OutboundDelegateMsgType::common_GetSecretResponse,
1326                                inbound: Some(response_offset.as_union_value()),
1327                            },
1328                        );
1329                        messages.push(msg);
1330                    }
1331                });
1332                let messages_offset = builder.create_vector(&messages);
1333                let delegate_response_offset = FbsDelegateResponse::create(
1334                    &mut builder,
1335                    &DelegateResponseArgs {
1336                        key: Some(key_offset),
1337                        values: Some(messages_offset),
1338                    },
1339                );
1340                let host_response_offset = FbsHostResponse::create(
1341                    &mut builder,
1342                    &HostResponseArgs {
1343                        response_type: HostResponseType::DelegateResponse,
1344                        response: Some(delegate_response_offset.as_union_value()),
1345                    },
1346                );
1347                finish_host_response_buffer(&mut builder, host_response_offset);
1348                Ok(builder.finished_data().to_vec())
1349            }
1350            HostResponse::Ok => {
1351                let ok_offset = FbsOk::create(&mut builder, &OkArgs { msg: None });
1352                let host_response_offset = FbsHostResponse::create(
1353                    &mut builder,
1354                    &HostResponseArgs {
1355                        response_type: HostResponseType::Ok,
1356                        response: Some(ok_offset.as_union_value()),
1357                    },
1358                );
1359                finish_host_response_buffer(&mut builder, host_response_offset);
1360                Ok(builder.finished_data().to_vec())
1361            }
1362            HostResponse::QueryResponse(_) => unimplemented!(),
1363        }
1364    }
1365}
1366
1367impl Display for HostResponse {
1368    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1369        match self {
1370            HostResponse::ContractResponse(res) => match res {
1371                ContractResponse::PutResponse { key } => {
1372                    f.write_fmt(format_args!("put response for `{key}`"))
1373                }
1374                ContractResponse::UpdateResponse { key, .. } => {
1375                    f.write_fmt(format_args!("update response for `{key}`"))
1376                }
1377                ContractResponse::GetResponse { key, .. } => {
1378                    f.write_fmt(format_args!("get response for `{key}`"))
1379                }
1380                ContractResponse::UpdateNotification { key, .. } => {
1381                    f.write_fmt(format_args!("update notification for `{key}`"))
1382                }
1383                ContractResponse::SubscribeResponse { key, .. } => {
1384                    f.write_fmt(format_args!("subscribe response for `{key}`"))
1385                }
1386            },
1387            HostResponse::DelegateResponse { .. } => write!(f, "delegate responses"),
1388            HostResponse::Ok => write!(f, "ok response"),
1389            HostResponse::QueryResponse(_) => write!(f, "query response"),
1390        }
1391    }
1392}
1393
1394#[derive(Clone, Serialize, Deserialize, Debug)]
1395#[non_exhaustive]
1396pub enum ContractResponse<T = WrappedState> {
1397    GetResponse {
1398        key: ContractKey,
1399        contract: Option<ContractContainer>,
1400        #[serde(bound(deserialize = "T: DeserializeOwned"))]
1401        state: T,
1402    },
1403    PutResponse {
1404        key: ContractKey,
1405    },
1406    /// Message sent when there is an update to a subscribed contract.
1407    UpdateNotification {
1408        key: ContractKey,
1409        #[serde(deserialize_with = "UpdateData::deser_update_data")]
1410        update: UpdateData<'static>,
1411    },
1412    /// Successful update
1413    UpdateResponse {
1414        key: ContractKey,
1415        #[serde(deserialize_with = "StateSummary::deser_state_summary")]
1416        summary: StateSummary<'static>,
1417    },
1418    SubscribeResponse {
1419        key: ContractKey,
1420        subscribed: bool,
1421    },
1422}
1423
1424impl<T> From<ContractResponse<T>> for HostResponse<T> {
1425    fn from(value: ContractResponse<T>) -> HostResponse<T> {
1426        HostResponse::ContractResponse(value)
1427    }
1428}
1429
1430#[cfg(test)]
1431mod client_request_test {
1432    use crate::client_api::{ContractRequest, TryFromFbs};
1433    use crate::contract_interface::UpdateData;
1434    use crate::generated::client_request::root_as_client_request;
1435
1436    const EXPECTED_ENCODED_CONTRACT_ID: &str = "6kVs66bKaQAC6ohr8b43SvJ95r36tc2hnG7HezmaJHF9";
1437
1438    #[test]
1439    fn test_build_contract_put_op_from_fbs() -> Result<(), Box<dyn std::error::Error>> {
1440        let put_req_op = vec![
1441            4, 0, 0, 0, 244, 255, 255, 255, 16, 0, 0, 0, 0, 0, 0, 1, 8, 0, 12, 0, 11, 0, 4, 0, 8,
1442            0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 1, 198, 255, 255, 255, 12, 0, 0, 0, 20, 0, 0, 0, 36, 0,
1443            0, 0, 170, 255, 255, 255, 4, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8,
1444            8, 0, 10, 0, 9, 0, 4, 0, 8, 0, 0, 0, 16, 0, 0, 0, 0, 1, 10, 0, 16, 0, 12, 0, 8, 0, 4,
1445            0, 10, 0, 0, 0, 12, 0, 0, 0, 76, 0, 0, 0, 92, 0, 0, 0, 176, 255, 255, 255, 8, 0, 0, 0,
1446            16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 8, 0, 4, 0, 6, 0, 0, 0, 4, 0, 0, 0, 32, 0, 0, 0,
1447            85, 111, 11, 171, 40, 85, 240, 177, 207, 81, 106, 157, 173, 90, 234, 2, 250, 253, 75,
1448            210, 62, 7, 6, 34, 75, 26, 229, 230, 107, 167, 17, 108, 8, 0, 0, 0, 1, 2, 3, 4, 5, 6,
1449            7, 8, 8, 0, 12, 0, 8, 0, 4, 0, 8, 0, 0, 0, 8, 0, 0, 0, 16, 0, 0, 0, 8, 0, 0, 0, 1, 2,
1450            3, 4, 5, 6, 7, 8, 8, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8,
1451        ];
1452        let request = if let Ok(client_request) = root_as_client_request(&put_req_op) {
1453            let contract_request = client_request.client_request_as_contract_request().unwrap();
1454            ContractRequest::try_decode_fbs(&contract_request)?
1455        } else {
1456            panic!("failed to decode client request")
1457        };
1458
1459        match request {
1460            ContractRequest::Put {
1461                contract,
1462                state,
1463                related_contracts: _,
1464                subscribe,
1465            } => {
1466                assert_eq!(
1467                    contract.to_string(),
1468                    "WasmContainer([api=0.0.1](D8fdVLbRyMLw5mZtPRpWMFcrXGN2z8Nq8UGcLGPFBg2W))"
1469                );
1470                assert_eq!(contract.unwrap_v1().data.data(), &[1, 2, 3, 4, 5, 6, 7, 8]);
1471                assert_eq!(state.to_vec(), &[1, 2, 3, 4, 5, 6, 7, 8]);
1472                assert!(!subscribe);
1473            }
1474            _ => panic!("wrong contract request type"),
1475        }
1476
1477        Ok(())
1478    }
1479
1480    #[test]
1481    fn test_build_contract_get_op_from_fbs() -> Result<(), Box<dyn std::error::Error>> {
1482        let get_req_op = vec![
1483            4, 0, 0, 0, 244, 255, 255, 255, 16, 0, 0, 0, 0, 0, 0, 1, 8, 0, 12, 0, 11, 0, 4, 0, 8,
1484            0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 3, 222, 255, 255, 255, 12, 0, 0, 0, 8, 0, 12, 0, 8, 0, 4,
1485            0, 8, 0, 0, 0, 8, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 8, 0, 4, 0, 6, 0, 0, 0,
1486            4, 0, 0, 0, 32, 0, 0, 0, 85, 111, 11, 171, 40, 85, 240, 177, 207, 81, 106, 157, 173,
1487            90, 234, 2, 250, 253, 75, 210, 62, 7, 6, 34, 75, 26, 229, 230, 107, 167, 17, 108,
1488        ];
1489        let request = if let Ok(client_request) = root_as_client_request(&get_req_op) {
1490            let contract_request = client_request.client_request_as_contract_request().unwrap();
1491            ContractRequest::try_decode_fbs(&contract_request)?
1492        } else {
1493            panic!("failed to decode client request")
1494        };
1495
1496        match request {
1497            ContractRequest::Get {
1498                key,
1499                return_contract_code: fetch_contract,
1500                subscribe,
1501            } => {
1502                assert_eq!(key.encoded_contract_id(), EXPECTED_ENCODED_CONTRACT_ID);
1503                assert!(!fetch_contract);
1504                assert!(!subscribe);
1505            }
1506            _ => panic!("wrong contract request type"),
1507        }
1508
1509        Ok(())
1510    }
1511
1512    #[test]
1513    fn test_build_contract_update_op_from_fbs() -> Result<(), Box<dyn std::error::Error>> {
1514        let update_op = vec![
1515            4, 0, 0, 0, 220, 255, 255, 255, 8, 0, 0, 0, 0, 0, 0, 1, 232, 255, 255, 255, 8, 0, 0, 0,
1516            0, 0, 0, 2, 204, 255, 255, 255, 16, 0, 0, 0, 52, 0, 0, 0, 8, 0, 12, 0, 11, 0, 4, 0, 8,
1517            0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 2, 210, 255, 255, 255, 4, 0, 0, 0, 8, 0, 0, 0, 1, 2, 3,
1518            4, 5, 6, 7, 8, 8, 0, 12, 0, 8, 0, 4, 0, 8, 0, 0, 0, 8, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0,
1519            0, 0, 0, 6, 0, 8, 0, 4, 0, 6, 0, 0, 0, 4, 0, 0, 0, 32, 0, 0, 0, 85, 111, 11, 171, 40,
1520            85, 240, 177, 207, 81, 106, 157, 173, 90, 234, 2, 250, 253, 75, 210, 62, 7, 6, 34, 75,
1521            26, 229, 230, 107, 167, 17, 108,
1522        ];
1523        let request = if let Ok(client_request) = root_as_client_request(&update_op) {
1524            let contract_request = client_request.client_request_as_contract_request().unwrap();
1525            ContractRequest::try_decode_fbs(&contract_request)?
1526        } else {
1527            panic!("failed to decode client request")
1528        };
1529
1530        match request {
1531            ContractRequest::Update { key, data } => {
1532                assert_eq!(
1533                    key.encoded_contract_id(),
1534                    "6kVs66bKaQAC6ohr8b43SvJ95r36tc2hnG7HezmaJHF9"
1535                );
1536                match data {
1537                    UpdateData::Delta(delta) => {
1538                        assert_eq!(delta.to_vec(), &[1, 2, 3, 4, 5, 6, 7, 8])
1539                    }
1540                    _ => panic!("wrong update data type"),
1541                }
1542            }
1543            _ => panic!("wrong contract request type"),
1544        }
1545
1546        Ok(())
1547    }
1548}