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