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