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 as FbsContractInstanceId, ContractInstanceIdArgs,
19 ContractKey as FbsContractKey, ContractKeyArgs, ContractType, DeltaUpdate, DeltaUpdateArgs,
20 GetSecretRequest as FbsGetSecretRequest, GetSecretRequestArgs,
21 GetSecretResponse as FbsGetSecretResponse, GetSecretResponseArgs, RelatedDeltaUpdate,
22 RelatedDeltaUpdateArgs, RelatedStateAndDeltaUpdate, RelatedStateAndDeltaUpdateArgs,
23 RelatedStateUpdate, RelatedStateUpdateArgs, SecretsId as FbsSecretsId, SecretsIdArgs,
24 StateAndDeltaUpdate, StateAndDeltaUpdateArgs, StateUpdate, StateUpdateArgs,
25 UpdateData as FbsUpdateData, UpdateDataArgs, UpdateDataType, WasmContractV1,
26 WasmContractV1Args,
27};
28use crate::generated::host_response::{
29 finish_host_response_buffer, ClientResponse as FbsClientResponse, ClientResponseArgs,
30 ContextUpdated as FbsContextUpdated, ContextUpdatedArgs,
31 ContractResponse as FbsContractResponse, ContractResponseArgs, ContractResponseType,
32 DelegateKey as FbsDelegateKey, DelegateKeyArgs, DelegateResponse as FbsDelegateResponse,
33 DelegateResponseArgs, GetResponse as FbsGetResponse, GetResponseArgs,
34 HostResponse as FbsHostResponse, HostResponseArgs, HostResponseType, NotFound as FbsNotFound,
35 NotFoundArgs, Ok as FbsOk, OkArgs, OutboundDelegateMsg as FbsOutboundDelegateMsg,
36 OutboundDelegateMsgArgs, OutboundDelegateMsgType, PutResponse as FbsPutResponse,
37 PutResponseArgs, RequestUserInput as FbsRequestUserInput, RequestUserInputArgs,
38 SetSecretRequest as FbsSetSecretRequest, SetSecretRequestArgs,
39 UpdateNotification as FbsUpdateNotification, UpdateNotificationArgs,
40 UpdateResponse as FbsUpdateResponse, UpdateResponseArgs,
41};
42use crate::prelude::ContractContainer::Wasm;
43use crate::prelude::ContractWasmAPIVersion::V1;
44use crate::prelude::UpdateData::{
45 Delta, RelatedDelta, RelatedState, RelatedStateAndDelta, State, StateAndDelta,
46};
47use crate::{
48 delegate_interface::{DelegateKey, InboundDelegateMsg, OutboundDelegateMsg},
49 prelude::{
50 ContractInstanceId, ContractKey, DelegateContainer, GetSecretRequest, Parameters,
51 RelatedContracts, SecretsId, StateSummary, UpdateData, WrappedState,
52 },
53 versioning::ContractContainer,
54};
55
56use super::WsApiError;
57
58#[derive(Debug, Serialize, Deserialize, Clone)]
59pub struct ClientError {
60 kind: Box<ErrorKind>,
61}
62
63impl ClientError {
64 pub fn into_fbs_bytes(self) -> Result<Vec<u8>, Box<ClientError>> {
65 use crate::generated::host_response::{Error, ErrorArgs};
66 let mut builder = flatbuffers::FlatBufferBuilder::new();
67 let msg_offset = builder.create_string(&self.to_string());
68 let err_offset = Error::create(
69 &mut builder,
70 &ErrorArgs {
71 msg: Some(msg_offset),
72 },
73 );
74 let host_response_offset = FbsHostResponse::create(
75 &mut builder,
76 &HostResponseArgs {
77 response_type: HostResponseType::Ok,
78 response: Some(err_offset.as_union_value()),
79 },
80 );
81 finish_host_response_buffer(&mut builder, host_response_offset);
82 Ok(builder.finished_data().to_vec())
83 }
84
85 pub fn kind(&self) -> &ErrorKind {
86 &self.kind
87 }
88}
89
90impl From<ErrorKind> for ClientError {
91 fn from(kind: ErrorKind) -> Self {
92 ClientError {
93 kind: Box::new(kind),
94 }
95 }
96}
97
98impl<T: Into<Cow<'static, str>>> From<T> for ClientError {
99 fn from(cause: T) -> Self {
100 ClientError {
101 kind: Box::new(ErrorKind::Unhandled {
102 cause: cause.into(),
103 }),
104 }
105 }
106}
107
108#[derive(thiserror::Error, Debug, Serialize, Deserialize, Clone)]
109#[non_exhaustive]
110pub enum ErrorKind {
111 #[error("comm channel between client/host closed")]
112 ChannelClosed,
113 #[error("error while deserializing: {cause}")]
114 DeserializationError { cause: Cow<'static, str> },
115 #[error("client disconnected")]
116 Disconnect,
117 #[error("failed while trying to unpack state for {0}")]
118 IncorrectState(ContractKey),
119 #[error("node not available")]
120 NodeUnavailable,
121 #[error("lost the connection with the protocol handling connections")]
122 TransportProtocolDisconnect,
123 #[error("unhandled error: {cause}")]
124 Unhandled { cause: Cow<'static, str> },
125 #[error("unknown client id: {0}")]
126 UnknownClient(usize),
127 #[error(transparent)]
128 RequestError(#[from] RequestError),
129 #[error("error while executing operation in the network: {cause}")]
130 OperationError { cause: Cow<'static, str> },
131 #[error("operation timed out")]
133 FailedOperation,
134 #[error("peer should shutdown")]
135 Shutdown,
136}
137
138impl Display for ClientError {
139 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
140 write!(f, "client error: {}", self.kind)
141 }
142}
143
144impl std::error::Error for ClientError {}
145
146#[derive(Debug, thiserror::Error, Serialize, Deserialize, Clone)]
147#[non_exhaustive]
148pub enum RequestError {
149 #[error(transparent)]
150 ContractError(#[from] ContractError),
151 #[error(transparent)]
152 DelegateError(#[from] DelegateError),
153 #[error("client disconnect")]
154 Disconnect,
155 #[error("operation timed out")]
156 Timeout,
157}
158
159#[derive(Debug, thiserror::Error, Serialize, Deserialize, Clone)]
161#[non_exhaustive]
162pub enum DelegateError {
163 #[error("error while registering delegate {0}")]
164 RegisterError(DelegateKey),
165 #[error("execution error, cause {0}")]
166 ExecutionError(Cow<'static, str>),
167 #[error("missing delegate {0}")]
168 Missing(DelegateKey),
169 #[error("missing secret `{secret}` for delegate {key}")]
170 MissingSecret { key: DelegateKey, secret: SecretsId },
171 #[error("forbidden access to secret: {0}")]
172 ForbiddenSecretAccess(SecretsId),
173}
174
175#[derive(Debug, thiserror::Error, Serialize, Deserialize, Clone)]
177#[non_exhaustive]
178pub enum ContractError {
179 #[error("failed to get contract {key}, reason: {cause}")]
180 Get {
181 key: ContractKey,
182 cause: Cow<'static, str>,
183 },
184 #[error("put error for contract {key}, reason: {cause}")]
185 Put {
186 key: ContractKey,
187 cause: Cow<'static, str>,
188 },
189 #[error("update error for contract {key}, reason: {cause}")]
190 Update {
191 key: ContractKey,
192 cause: Cow<'static, str>,
193 },
194 #[error("failed to subscribe for contract {key}, reason: {cause}")]
195 Subscribe {
196 key: ContractKey,
197 cause: Cow<'static, str>,
198 },
199 #[error("dependency contract stack overflow : {key}")]
201 ContractStackOverflow {
202 key: crate::contract_interface::ContractInstanceId,
203 },
204 #[error("missing related contract: {key}")]
205 MissingRelated {
206 key: crate::contract_interface::ContractInstanceId,
207 },
208 #[error("missing contract: {key}")]
209 MissingContract {
210 key: crate::contract_interface::ContractInstanceId,
211 },
212}
213
214impl ContractError {
215 const EXECUTION_ERROR: &'static str = "execution error";
216 const INVALID_PUT: &'static str = "invalid put";
217
218 pub fn update_exec_error(key: ContractKey, additional_info: impl std::fmt::Display) -> Self {
219 Self::Update {
220 key,
221 cause: format!(
222 "{exec_err}: {additional_info}",
223 exec_err = Self::EXECUTION_ERROR
224 )
225 .into(),
226 }
227 }
228
229 pub fn invalid_put(key: ContractKey) -> Self {
230 Self::Put {
231 key,
232 cause: Self::INVALID_PUT.into(),
233 }
234 }
235
236 pub fn invalid_update(key: ContractKey) -> Self {
237 Self::Update {
238 key,
239 cause: Self::INVALID_PUT.into(),
240 }
241 }
242}
243
244#[derive(Serialize, Deserialize, Debug, Clone)]
246#[non_exhaustive]
247pub enum ClientRequest<'a> {
249 DelegateOp(#[serde(borrow)] DelegateRequest<'a>),
250 ContractOp(#[serde(borrow)] ContractRequest<'a>),
251 Disconnect {
252 cause: Option<Cow<'static, str>>,
253 },
254 Authenticate {
255 token: String,
256 },
257 NodeQueries(NodeQuery),
258 Close,
260}
261
262#[derive(Serialize, Deserialize, Debug, Clone)]
263pub struct ConnectedPeers {}
264
265#[derive(Serialize, Deserialize, Debug, Clone)]
266pub struct NodeDiagnostics {
267 pub contract_key: Option<ContractKey>,
269}
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 blocking_subscribe,
282 } => {
283 let related_contracts = related_contracts.into_owned();
284 ContractRequest::Put {
285 contract,
286 state,
287 related_contracts,
288 subscribe,
289 blocking_subscribe,
290 }
291 }
292 ContractRequest::Update { key, data } => {
293 let data = data.into_owned();
294 ContractRequest::Update { key, data }
295 }
296 ContractRequest::Get {
297 key,
298 return_contract_code,
299 subscribe,
300 blocking_subscribe,
301 } => ContractRequest::Get {
302 key,
303 return_contract_code,
304 subscribe,
305 blocking_subscribe,
306 },
307 ContractRequest::Subscribe { key, summary } => ContractRequest::Subscribe {
308 key,
309 summary: summary.map(StateSummary::into_owned),
310 },
311 };
312 owned.into()
313 }
314 ClientRequest::DelegateOp(op) => {
315 let op = op.into_owned();
316 ClientRequest::DelegateOp(op)
317 }
318 ClientRequest::Disconnect { cause } => ClientRequest::Disconnect { cause },
319 ClientRequest::Authenticate { token } => ClientRequest::Authenticate { token },
320 ClientRequest::NodeQueries(query) => ClientRequest::NodeQueries(query),
321 ClientRequest::Close => ClientRequest::Close,
322 }
323 }
324
325 pub fn is_disconnect(&self) -> bool {
326 matches!(self, Self::Disconnect { .. })
327 }
328
329 pub fn try_decode_fbs(msg: &[u8]) -> Result<ClientRequest<'_>, WsApiError> {
330 let req = {
331 match root_as_client_request(msg) {
332 Ok(client_request) => match client_request.client_request_type() {
333 ClientRequestType::ContractRequest => {
334 let contract_request =
335 client_request.client_request_as_contract_request().unwrap();
336 ContractRequest::try_decode_fbs(&contract_request)?.into()
337 }
338 ClientRequestType::DelegateRequest => {
339 let delegate_request =
340 client_request.client_request_as_delegate_request().unwrap();
341 DelegateRequest::try_decode_fbs(&delegate_request)?.into()
342 }
343 ClientRequestType::Disconnect => {
344 let delegate_request =
345 client_request.client_request_as_disconnect().unwrap();
346 let cause = delegate_request
347 .cause()
348 .map(|cause_msg| cause_msg.to_string().into());
349 ClientRequest::Disconnect { cause }
350 }
351 ClientRequestType::Authenticate => {
352 let auth_req = client_request.client_request_as_authenticate().unwrap();
353 let token = auth_req.token();
354 ClientRequest::Authenticate {
355 token: token.to_owned(),
356 }
357 }
358 _ => unreachable!(),
359 },
360 Err(e) => {
361 let cause = format!("{e}");
362 return Err(WsApiError::deserialization(cause));
363 }
364 }
365 };
366
367 Ok(req)
368 }
369}
370
371#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
372#[non_exhaustive]
373pub enum ContractRequest<'a> {
374 Put {
376 contract: ContractContainer,
377 state: WrappedState,
379 #[serde(borrow)]
381 related_contracts: RelatedContracts<'a>,
382 subscribe: bool,
384 #[serde(default)]
387 blocking_subscribe: bool,
388 },
389 Update {
391 key: ContractKey,
392 #[serde(borrow)]
393 data: UpdateData<'a>,
394 },
395 Get {
397 key: ContractInstanceId,
400 return_contract_code: bool,
402 subscribe: bool,
404 #[serde(default)]
407 blocking_subscribe: bool,
408 },
409 Subscribe {
412 key: ContractInstanceId,
414 summary: Option<StateSummary<'a>>,
415 },
416}
417
418impl ContractRequest<'_> {
419 pub fn into_owned(self) -> ContractRequest<'static> {
420 match self {
421 Self::Put {
422 contract,
423 state,
424 related_contracts,
425 subscribe,
426 blocking_subscribe,
427 } => ContractRequest::Put {
428 contract,
429 state,
430 related_contracts: related_contracts.into_owned(),
431 subscribe,
432 blocking_subscribe,
433 },
434 Self::Update { key, data } => ContractRequest::Update {
435 key,
436 data: data.into_owned(),
437 },
438 Self::Get {
439 key,
440 return_contract_code: fetch_contract,
441 subscribe,
442 blocking_subscribe,
443 } => ContractRequest::Get {
444 key,
445 return_contract_code: fetch_contract,
446 subscribe,
447 blocking_subscribe,
448 },
449 Self::Subscribe { key, summary } => ContractRequest::Subscribe {
450 key,
451 summary: summary.map(StateSummary::into_owned),
452 },
453 }
454 }
455}
456
457impl<'a> From<ContractRequest<'a>> for ClientRequest<'a> {
458 fn from(op: ContractRequest<'a>) -> Self {
459 ClientRequest::ContractOp(op)
460 }
461}
462
463impl<'a> TryFromFbs<&FbsContractRequest<'a>> for ContractRequest<'a> {
465 fn try_decode_fbs(request: &FbsContractRequest<'a>) -> Result<Self, WsApiError> {
466 let req = {
467 match request.contract_request_type() {
468 ContractRequestType::Get => {
469 let get = request.contract_request_as_get().unwrap();
470 let fbs_key = get.key();
473 let key_bytes: [u8; 32] = fbs_key.instance().data().bytes().try_into().unwrap();
474 let key = ContractInstanceId::new(key_bytes);
475 let fetch_contract = get.fetch_contract();
476 let subscribe = get.subscribe();
477 let blocking_subscribe = get.blocking_subscribe();
478 ContractRequest::Get {
479 key,
480 return_contract_code: fetch_contract,
481 subscribe,
482 blocking_subscribe,
483 }
484 }
485 ContractRequestType::Put => {
486 let put = request.contract_request_as_put().unwrap();
487 let contract = ContractContainer::try_decode_fbs(&put.container())?;
488 let state = WrappedState::new(put.wrapped_state().bytes().to_vec());
489 let related_contracts =
490 RelatedContracts::try_decode_fbs(&put.related_contracts())?.into_owned();
491 let subscribe = put.subscribe();
492 let blocking_subscribe = put.blocking_subscribe();
493 ContractRequest::Put {
494 contract,
495 state,
496 related_contracts,
497 subscribe,
498 blocking_subscribe,
499 }
500 }
501 ContractRequestType::Update => {
502 let update = request.contract_request_as_update().unwrap();
503 let key = ContractKey::try_decode_fbs(&update.key())?;
504 let data = UpdateData::try_decode_fbs(&update.data())?.into_owned();
505 ContractRequest::Update { key, data }
506 }
507 ContractRequestType::Subscribe => {
508 let subscribe = request.contract_request_as_subscribe().unwrap();
509 let fbs_key = subscribe.key();
511 let key_bytes: [u8; 32] = fbs_key.instance().data().bytes().try_into().unwrap();
512 let key = ContractInstanceId::new(key_bytes);
513 let summary = subscribe
514 .summary()
515 .map(|summary_data| StateSummary::from(summary_data.bytes()));
516 ContractRequest::Subscribe { key, summary }
517 }
518 _ => unreachable!(),
519 }
520 };
521
522 Ok(req)
523 }
524}
525
526impl<'a> From<DelegateRequest<'a>> for ClientRequest<'a> {
527 fn from(op: DelegateRequest<'a>) -> Self {
528 ClientRequest::DelegateOp(op)
529 }
530}
531
532#[derive(Serialize, Deserialize, Debug, Clone)]
533#[non_exhaustive]
534pub enum DelegateRequest<'a> {
535 ApplicationMessages {
536 key: DelegateKey,
537 #[serde(deserialize_with = "Parameters::deser_params")]
538 params: Parameters<'a>,
539 #[serde(borrow)]
540 inbound: Vec<InboundDelegateMsg<'a>>,
541 },
542 GetSecretRequest {
543 key: DelegateKey,
544 #[serde(borrow)]
545 params: Parameters<'a>,
546 get_request: GetSecretRequest,
547 },
548 RegisterDelegate {
549 delegate: DelegateContainer,
550 cipher: [u8; 32],
551 nonce: [u8; 24],
552 },
553 UnregisterDelegate(DelegateKey),
554}
555
556impl DelegateRequest<'_> {
557 pub const DEFAULT_CIPHER: [u8; 32] = [
558 0, 24, 22, 150, 112, 207, 24, 65, 182, 161, 169, 227, 66, 182, 237, 215, 206, 164, 58, 161,
559 64, 108, 157, 195, 0, 0, 0, 0, 0, 0, 0, 0,
560 ];
561
562 pub const DEFAULT_NONCE: [u8; 24] = [
563 57, 18, 79, 116, 63, 134, 93, 39, 208, 161, 156, 229, 222, 247, 111, 79, 210, 126, 127, 55,
564 224, 150, 139, 80,
565 ];
566
567 pub fn into_owned(self) -> DelegateRequest<'static> {
568 match self {
569 DelegateRequest::ApplicationMessages {
570 key,
571 inbound,
572 params,
573 } => DelegateRequest::ApplicationMessages {
574 key,
575 params: params.into_owned(),
576 inbound: inbound.into_iter().map(|e| e.into_owned()).collect(),
577 },
578 DelegateRequest::GetSecretRequest {
579 key,
580 get_request,
581 params,
582 } => DelegateRequest::GetSecretRequest {
583 key,
584 get_request,
585 params: params.into_owned(),
586 },
587 DelegateRequest::RegisterDelegate {
588 delegate,
589 cipher,
590 nonce,
591 } => DelegateRequest::RegisterDelegate {
592 delegate,
593 cipher,
594 nonce,
595 },
596 DelegateRequest::UnregisterDelegate(key) => DelegateRequest::UnregisterDelegate(key),
597 }
598 }
599
600 pub fn key(&self) -> &DelegateKey {
601 match self {
602 DelegateRequest::ApplicationMessages { key, .. } => key,
603 DelegateRequest::GetSecretRequest { key, .. } => key,
604 DelegateRequest::RegisterDelegate { delegate, .. } => delegate.key(),
605 DelegateRequest::UnregisterDelegate(key) => key,
606 }
607 }
608}
609
610impl Display for ClientRequest<'_> {
611 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
612 match self {
613 ClientRequest::ContractOp(op) => match op {
614 ContractRequest::Put {
615 contract, state, ..
616 } => {
617 write!(
618 f,
619 "ContractRequest::Put for contract `{contract}` with state {state}"
620 )
621 }
622 ContractRequest::Update { key, .. } => write!(f, "update request for {key}"),
623 ContractRequest::Get {
624 key,
625 return_contract_code: contract,
626 ..
627 } => {
628 write!(
629 f,
630 "ContractRequest::Get for key `{key}` (fetch full contract: {contract})"
631 )
632 }
633 ContractRequest::Subscribe { key, .. } => {
634 write!(f, "ContractRequest::Subscribe for `{key}`")
635 }
636 },
637 ClientRequest::DelegateOp(op) => {
638 match op {
639 DelegateRequest::ApplicationMessages { key, inbound, .. } => {
640 write!(
641 f,
642 "DelegateRequest::ApplicationMessages for `{key}` with {} messages",
643 inbound.len()
644 )
645 }
646 DelegateRequest::GetSecretRequest {
647 get_request: GetSecretRequest { key: secret_id, .. },
648 key,
649 ..
650 } => {
651 write!(f, "DelegateRequest::GetSecretRequest secret_id `{secret_id}` for key `{key}`")
652 }
653 DelegateRequest::RegisterDelegate { delegate, .. } => {
654 write!(
655 f,
656 "DelegateRequest::RegisterDelegate for delegate.key()=`{}`",
657 delegate.key()
658 )
659 }
660 DelegateRequest::UnregisterDelegate(key) => {
661 write!(f, "DelegateRequest::UnregisterDelegate for key `{key}`")
662 }
663 }
664 }
665 ClientRequest::Disconnect { .. } => write!(f, "client disconnected"),
666 ClientRequest::Authenticate { .. } => write!(f, "authenticate"),
667 ClientRequest::NodeQueries(query) => write!(f, "node queries: {:?}", query),
668 ClientRequest::Close => write!(f, "close"),
669 }
670 }
671}
672
673impl<'a> TryFromFbs<&FbsDelegateRequest<'a>> for DelegateRequest<'a> {
675 fn try_decode_fbs(request: &FbsDelegateRequest<'a>) -> Result<Self, WsApiError> {
676 let req = {
677 match request.delegate_request_type() {
678 DelegateRequestType::ApplicationMessages => {
679 let app_msg = request.delegate_request_as_application_messages().unwrap();
680 let key = DelegateKey::try_decode_fbs(&app_msg.key())?;
681 let params = Parameters::from(app_msg.params().bytes());
682 let inbound = app_msg
683 .inbound()
684 .iter()
685 .map(|msg| InboundDelegateMsg::try_decode_fbs(&msg))
686 .collect::<Result<Vec<_>, _>>()?;
687 DelegateRequest::ApplicationMessages {
688 key,
689 params,
690 inbound,
691 }
692 }
693 DelegateRequestType::GetSecretRequestType => {
694 let get_secret = request
695 .delegate_request_as_get_secret_request_type()
696 .unwrap();
697 let key = DelegateKey::try_decode_fbs(&get_secret.key())?;
698 let params = Parameters::from(get_secret.params().bytes().to_vec());
699 let get_request = GetSecretRequest {
700 key: SecretsId::try_decode_fbs(&get_secret.get_request().key())?,
701 context: DelegateContext::new(
702 get_secret.get_request().delegate_context().bytes().to_vec(),
703 ),
704 processed: get_secret.get_request().processed(),
705 };
706 DelegateRequest::GetSecretRequest {
707 key,
708 params,
709 get_request,
710 }
711 }
712 DelegateRequestType::RegisterDelegate => {
713 let register = request.delegate_request_as_register_delegate().unwrap();
714 let delegate = DelegateContainer::try_decode_fbs(®ister.delegate())?;
715 let cipher =
716 <[u8; 32]>::try_from(register.cipher().bytes().to_vec().as_slice())
717 .unwrap();
718 let nonce =
719 <[u8; 24]>::try_from(register.nonce().bytes().to_vec().as_slice()).unwrap();
720 DelegateRequest::RegisterDelegate {
721 delegate,
722 cipher,
723 nonce,
724 }
725 }
726 DelegateRequestType::UnregisterDelegate => {
727 let unregister = request.delegate_request_as_unregister_delegate().unwrap();
728 let key = DelegateKey::try_decode_fbs(&unregister.key())?;
729 DelegateRequest::UnregisterDelegate(key)
730 }
731 _ => unreachable!(),
732 }
733 };
734
735 Ok(req)
736 }
737}
738
739#[derive(Serialize, Deserialize, Debug, Clone)]
741#[non_exhaustive]
742pub enum HostResponse<T = WrappedState> {
743 ContractResponse(#[serde(bound(deserialize = "T: DeserializeOwned"))] ContractResponse<T>),
744 DelegateResponse {
745 key: DelegateKey,
746 values: Vec<OutboundDelegateMsg>,
747 },
748 QueryResponse(QueryResponse),
749 Ok,
751}
752
753type Peer = String;
754
755#[derive(Serialize, Deserialize, Debug, Clone)]
756pub enum QueryResponse {
757 ConnectedPeers { peers: Vec<(Peer, SocketAddr)> },
758 NetworkDebug(NetworkDebugInfo),
759 NodeDiagnostics(NodeDiagnosticsResponse),
760 ProximityCache(ProximityCacheInfo),
761}
762
763#[derive(Serialize, Deserialize, Debug, Clone)]
764pub struct NetworkDebugInfo {
765 pub subscriptions: Vec<SubscriptionInfo>,
766 pub connected_peers: Vec<(String, SocketAddr)>,
767}
768
769#[derive(Serialize, Deserialize, Debug, Clone)]
770pub struct NodeDiagnosticsResponse {
771 pub node_info: Option<NodeInfo>,
773
774 pub network_info: Option<NetworkInfo>,
776
777 pub subscriptions: Vec<SubscriptionInfo>,
779
780 pub contract_states: std::collections::HashMap<ContractKey, ContractState>,
782
783 pub system_metrics: Option<SystemMetrics>,
785
786 pub connected_peers_detailed: Vec<ConnectedPeerInfo>,
788}
789
790#[derive(Serialize, Deserialize, Debug, Clone)]
791pub struct NodeInfo {
792 pub peer_id: String,
793 pub is_gateway: bool,
794 pub location: Option<String>,
795 pub listening_address: Option<String>,
796 pub uptime_seconds: u64,
797}
798
799#[derive(Serialize, Deserialize, Debug, Clone)]
800pub struct NetworkInfo {
801 pub connected_peers: Vec<(String, String)>, pub active_connections: usize,
803}
804
805#[derive(Serialize, Deserialize, Debug, Clone)]
806pub struct ContractState {
807 pub subscribers: u32,
809 pub subscriber_peer_ids: Vec<String>,
811}
812
813#[derive(Serialize, Deserialize, Debug, Clone)]
814pub struct SystemMetrics {
815 pub active_connections: u32,
816 pub seeding_contracts: u32,
817}
818
819#[derive(Serialize, Deserialize, Debug, Clone)]
820pub struct SubscriptionInfo {
821 pub contract_key: ContractInstanceId,
822 pub client_id: usize,
823}
824
825#[derive(Serialize, Deserialize, Debug, Clone)]
827pub struct ConnectedPeerInfo {
828 pub peer_id: String,
829 pub address: String,
830}
831
832#[derive(Serialize, Deserialize, Debug, Clone)]
833pub enum NodeQuery {
834 ConnectedPeers,
835 SubscriptionInfo,
836 NodeDiagnostics {
837 config: NodeDiagnosticsConfig,
839 },
840 ProximityCacheInfo,
842}
843
844#[derive(Serialize, Deserialize, Debug, Clone)]
846pub struct ProximityCacheInfo {
847 pub my_cache: Vec<ContractCacheEntry>,
849 pub neighbor_caches: Vec<NeighborCacheInfo>,
851 pub stats: ProximityStats,
853}
854
855#[derive(Serialize, Deserialize, Debug, Clone)]
856pub struct ContractCacheEntry {
857 pub contract_key: String,
859 pub cache_hash: u32,
861 pub cached_since: u64,
863}
864
865#[derive(Serialize, Deserialize, Debug, Clone)]
866pub struct NeighborCacheInfo {
867 pub peer_id: String,
869 pub known_contracts: Vec<u32>,
871 pub last_update: u64,
873 pub update_count: u64,
875}
876
877#[derive(Serialize, Deserialize, Debug, Clone)]
878pub struct ProximityStats {
879 pub cache_announces_sent: u64,
881 pub cache_announces_received: u64,
883 pub updates_via_proximity: u64,
885 pub updates_via_subscription: u64,
887 pub false_positive_forwards: u64,
889 pub avg_neighbor_cache_size: f32,
891}
892
893#[derive(Serialize, Deserialize, Debug, Clone)]
894pub struct NodeDiagnosticsConfig {
895 pub include_node_info: bool,
897
898 pub include_network_info: bool,
900
901 pub include_subscriptions: bool,
903
904 pub contract_keys: Vec<ContractKey>,
906
907 pub include_system_metrics: bool,
909
910 pub include_detailed_peer_info: bool,
912
913 pub include_subscriber_peer_ids: bool,
915}
916
917impl NodeDiagnosticsConfig {
918 pub fn for_update_propagation_debugging(contract_key: ContractKey) -> Self {
920 Self {
921 include_node_info: true,
922 include_network_info: true,
923 include_subscriptions: true,
924 contract_keys: vec![contract_key],
925 include_system_metrics: true,
926 include_detailed_peer_info: true,
927 include_subscriber_peer_ids: true,
928 }
929 }
930
931 pub fn basic_status() -> Self {
933 Self {
934 include_node_info: true,
935 include_network_info: true,
936 include_subscriptions: false,
937 contract_keys: vec![],
938 include_system_metrics: false,
939 include_detailed_peer_info: false,
940 include_subscriber_peer_ids: false,
941 }
942 }
943
944 pub fn full() -> Self {
946 Self {
947 include_node_info: true,
948 include_network_info: true,
949 include_subscriptions: true,
950 contract_keys: vec![], include_system_metrics: true,
952 include_detailed_peer_info: true,
953 include_subscriber_peer_ids: true,
954 }
955 }
956}
957
958impl HostResponse {
959 pub fn unwrap_put(self) -> ContractKey {
960 if let Self::ContractResponse(ContractResponse::PutResponse { key }) = self {
961 key
962 } else {
963 panic!("called `HostResponse::unwrap_put()` on other than `PutResponse` value")
964 }
965 }
966
967 pub fn unwrap_get(self) -> (WrappedState, Option<ContractContainer>) {
968 if let Self::ContractResponse(ContractResponse::GetResponse {
969 contract, state, ..
970 }) = self
971 {
972 (state, contract)
973 } else {
974 panic!("called `HostResponse::unwrap_put()` on other than `PutResponse` value")
975 }
976 }
977
978 pub fn into_fbs_bytes(self) -> Result<Vec<u8>, Box<ClientError>> {
979 let mut builder = flatbuffers::FlatBufferBuilder::new();
980 match self {
981 HostResponse::ContractResponse(res) => match res {
982 ContractResponse::PutResponse { key } => {
983 let instance_data = builder.create_vector(key.as_bytes());
984 let instance_offset = FbsContractInstanceId::create(
985 &mut builder,
986 &ContractInstanceIdArgs {
987 data: Some(instance_data),
988 },
989 );
990
991 let code = Some(builder.create_vector(&key.code_hash().0));
992 let key_offset = FbsContractKey::create(
993 &mut builder,
994 &ContractKeyArgs {
995 instance: Some(instance_offset),
996 code,
997 },
998 );
999
1000 let put_offset = FbsPutResponse::create(
1001 &mut builder,
1002 &PutResponseArgs {
1003 key: Some(key_offset),
1004 },
1005 );
1006
1007 let contract_response_offset = FbsContractResponse::create(
1008 &mut builder,
1009 &ContractResponseArgs {
1010 contract_response: Some(put_offset.as_union_value()),
1011 contract_response_type: ContractResponseType::PutResponse,
1012 },
1013 );
1014
1015 let response_offset = FbsHostResponse::create(
1016 &mut builder,
1017 &HostResponseArgs {
1018 response: Some(contract_response_offset.as_union_value()),
1019 response_type: HostResponseType::ContractResponse,
1020 },
1021 );
1022
1023 finish_host_response_buffer(&mut builder, response_offset);
1024 Ok(builder.finished_data().to_vec())
1025 }
1026 ContractResponse::UpdateResponse { key, summary } => {
1027 let instance_data = builder.create_vector(key.as_bytes());
1028 let instance_offset = FbsContractInstanceId::create(
1029 &mut builder,
1030 &ContractInstanceIdArgs {
1031 data: Some(instance_data),
1032 },
1033 );
1034
1035 let code = Some(builder.create_vector(&key.code_hash().0));
1036
1037 let key_offset = FbsContractKey::create(
1038 &mut builder,
1039 &ContractKeyArgs {
1040 instance: Some(instance_offset),
1041 code,
1042 },
1043 );
1044
1045 let summary_data = builder.create_vector(&summary.into_bytes());
1046
1047 let update_response_offset = FbsUpdateResponse::create(
1048 &mut builder,
1049 &UpdateResponseArgs {
1050 key: Some(key_offset),
1051 summary: Some(summary_data),
1052 },
1053 );
1054
1055 let contract_response_offset = FbsContractResponse::create(
1056 &mut builder,
1057 &ContractResponseArgs {
1058 contract_response: Some(update_response_offset.as_union_value()),
1059 contract_response_type: ContractResponseType::UpdateResponse,
1060 },
1061 );
1062
1063 let response_offset = FbsHostResponse::create(
1064 &mut builder,
1065 &HostResponseArgs {
1066 response: Some(contract_response_offset.as_union_value()),
1067 response_type: HostResponseType::ContractResponse,
1068 },
1069 );
1070
1071 finish_host_response_buffer(&mut builder, response_offset);
1072 Ok(builder.finished_data().to_vec())
1073 }
1074 ContractResponse::GetResponse {
1075 key,
1076 contract: contract_container,
1077 state,
1078 } => {
1079 let instance_data = builder.create_vector(key.as_bytes());
1080 let instance_offset = FbsContractInstanceId::create(
1081 &mut builder,
1082 &ContractInstanceIdArgs {
1083 data: Some(instance_data),
1084 },
1085 );
1086
1087 let code = Some(builder.create_vector(&key.code_hash().0));
1088 let key_offset = FbsContractKey::create(
1089 &mut builder,
1090 &ContractKeyArgs {
1091 instance: Some(instance_offset),
1092 code,
1093 },
1094 );
1095
1096 let container_offset = if let Some(contract) = contract_container {
1097 let data = builder.create_vector(contract.key().as_bytes());
1098
1099 let instance_offset = FbsContractInstanceId::create(
1100 &mut builder,
1101 &ContractInstanceIdArgs { data: Some(data) },
1102 );
1103
1104 let code = Some(builder.create_vector(&contract.key().code_hash().0));
1105 let contract_key_offset = FbsContractKey::create(
1106 &mut builder,
1107 &ContractKeyArgs {
1108 instance: Some(instance_offset),
1109 code,
1110 },
1111 );
1112
1113 let contract_data =
1114 builder.create_vector(contract.clone().unwrap_v1().data.data());
1115 let contract_code_hash =
1116 builder.create_vector(&contract.clone().unwrap_v1().data.hash().0);
1117
1118 let contract_code_offset = ContractCode::create(
1119 &mut builder,
1120 &ContractCodeArgs {
1121 data: Some(contract_data),
1122 code_hash: Some(contract_code_hash),
1123 },
1124 );
1125
1126 let contract_params =
1127 builder.create_vector(&contract.clone().params().into_bytes());
1128
1129 let contract_offset = match contract {
1130 Wasm(V1(..)) => WasmContractV1::create(
1131 &mut builder,
1132 &WasmContractV1Args {
1133 key: Some(contract_key_offset),
1134 data: Some(contract_code_offset),
1135 parameters: Some(contract_params),
1136 },
1137 ),
1138 };
1139
1140 Some(FbsContractContainer::create(
1141 &mut builder,
1142 &ContractContainerArgs {
1143 contract_type: ContractType::WasmContractV1,
1144 contract: Some(contract_offset.as_union_value()),
1145 },
1146 ))
1147 } else {
1148 None
1149 };
1150
1151 let state_data = builder.create_vector(&state);
1152
1153 let get_offset = FbsGetResponse::create(
1154 &mut builder,
1155 &GetResponseArgs {
1156 key: Some(key_offset),
1157 contract: container_offset,
1158 state: Some(state_data),
1159 },
1160 );
1161
1162 let contract_response_offset = FbsContractResponse::create(
1163 &mut builder,
1164 &ContractResponseArgs {
1165 contract_response_type: ContractResponseType::GetResponse,
1166 contract_response: Some(get_offset.as_union_value()),
1167 },
1168 );
1169
1170 let response_offset = FbsHostResponse::create(
1171 &mut builder,
1172 &HostResponseArgs {
1173 response: Some(contract_response_offset.as_union_value()),
1174 response_type: HostResponseType::ContractResponse,
1175 },
1176 );
1177
1178 finish_host_response_buffer(&mut builder, response_offset);
1179 Ok(builder.finished_data().to_vec())
1180 }
1181 ContractResponse::UpdateNotification { key, update } => {
1182 let instance_data = builder.create_vector(key.as_bytes());
1183 let instance_offset = FbsContractInstanceId::create(
1184 &mut builder,
1185 &ContractInstanceIdArgs {
1186 data: Some(instance_data),
1187 },
1188 );
1189
1190 let code = Some(builder.create_vector(&key.code_hash().0));
1191 let key_offset = FbsContractKey::create(
1192 &mut builder,
1193 &ContractKeyArgs {
1194 instance: Some(instance_offset),
1195 code,
1196 },
1197 );
1198
1199 let update_data = match update {
1200 State(state) => {
1201 let state_data = builder.create_vector(&state.into_bytes());
1202 let state_update_offset = StateUpdate::create(
1203 &mut builder,
1204 &StateUpdateArgs {
1205 state: Some(state_data),
1206 },
1207 );
1208 FbsUpdateData::create(
1209 &mut builder,
1210 &UpdateDataArgs {
1211 update_data_type: UpdateDataType::StateUpdate,
1212 update_data: Some(state_update_offset.as_union_value()),
1213 },
1214 )
1215 }
1216 Delta(delta) => {
1217 let delta_data = builder.create_vector(&delta.into_bytes());
1218 let update_offset = DeltaUpdate::create(
1219 &mut builder,
1220 &DeltaUpdateArgs {
1221 delta: Some(delta_data),
1222 },
1223 );
1224 FbsUpdateData::create(
1225 &mut builder,
1226 &UpdateDataArgs {
1227 update_data_type: UpdateDataType::DeltaUpdate,
1228 update_data: Some(update_offset.as_union_value()),
1229 },
1230 )
1231 }
1232 StateAndDelta { state, delta } => {
1233 let state_data = builder.create_vector(&state.into_bytes());
1234 let delta_data = builder.create_vector(&delta.into_bytes());
1235
1236 let update_offset = StateAndDeltaUpdate::create(
1237 &mut builder,
1238 &StateAndDeltaUpdateArgs {
1239 state: Some(state_data),
1240 delta: Some(delta_data),
1241 },
1242 );
1243
1244 FbsUpdateData::create(
1245 &mut builder,
1246 &UpdateDataArgs {
1247 update_data_type: UpdateDataType::StateAndDeltaUpdate,
1248 update_data: Some(update_offset.as_union_value()),
1249 },
1250 )
1251 }
1252 RelatedState { related_to, state } => {
1253 let state_data = builder.create_vector(&state.into_bytes());
1254 let instance_data =
1255 builder.create_vector(related_to.encode().as_bytes());
1256
1257 let instance_offset = FbsContractInstanceId::create(
1258 &mut builder,
1259 &ContractInstanceIdArgs {
1260 data: Some(instance_data),
1261 },
1262 );
1263
1264 let update_offset = RelatedStateUpdate::create(
1265 &mut builder,
1266 &RelatedStateUpdateArgs {
1267 related_to: Some(instance_offset),
1268 state: Some(state_data),
1269 },
1270 );
1271
1272 FbsUpdateData::create(
1273 &mut builder,
1274 &UpdateDataArgs {
1275 update_data_type: UpdateDataType::RelatedStateUpdate,
1276 update_data: Some(update_offset.as_union_value()),
1277 },
1278 )
1279 }
1280 RelatedDelta { related_to, delta } => {
1281 let instance_data =
1282 builder.create_vector(related_to.encode().as_bytes());
1283 let delta_data = builder.create_vector(&delta.into_bytes());
1284
1285 let instance_offset = FbsContractInstanceId::create(
1286 &mut builder,
1287 &ContractInstanceIdArgs {
1288 data: Some(instance_data),
1289 },
1290 );
1291
1292 let update_offset = RelatedDeltaUpdate::create(
1293 &mut builder,
1294 &RelatedDeltaUpdateArgs {
1295 related_to: Some(instance_offset),
1296 delta: Some(delta_data),
1297 },
1298 );
1299
1300 FbsUpdateData::create(
1301 &mut builder,
1302 &UpdateDataArgs {
1303 update_data_type: UpdateDataType::RelatedDeltaUpdate,
1304 update_data: Some(update_offset.as_union_value()),
1305 },
1306 )
1307 }
1308 RelatedStateAndDelta {
1309 related_to,
1310 state,
1311 delta,
1312 } => {
1313 let instance_data =
1314 builder.create_vector(related_to.encode().as_bytes());
1315 let state_data = builder.create_vector(&state.into_bytes());
1316 let delta_data = builder.create_vector(&delta.into_bytes());
1317
1318 let instance_offset = FbsContractInstanceId::create(
1319 &mut builder,
1320 &ContractInstanceIdArgs {
1321 data: Some(instance_data),
1322 },
1323 );
1324
1325 let update_offset = RelatedStateAndDeltaUpdate::create(
1326 &mut builder,
1327 &RelatedStateAndDeltaUpdateArgs {
1328 related_to: Some(instance_offset),
1329 state: Some(state_data),
1330 delta: Some(delta_data),
1331 },
1332 );
1333
1334 FbsUpdateData::create(
1335 &mut builder,
1336 &UpdateDataArgs {
1337 update_data_type: UpdateDataType::RelatedStateAndDeltaUpdate,
1338 update_data: Some(update_offset.as_union_value()),
1339 },
1340 )
1341 }
1342 };
1343
1344 let update_notification_offset = FbsUpdateNotification::create(
1345 &mut builder,
1346 &UpdateNotificationArgs {
1347 key: Some(key_offset),
1348 update: Some(update_data),
1349 },
1350 );
1351
1352 let put_response_offset = FbsContractResponse::create(
1353 &mut builder,
1354 &ContractResponseArgs {
1355 contract_response_type: ContractResponseType::UpdateNotification,
1356 contract_response: Some(update_notification_offset.as_union_value()),
1357 },
1358 );
1359
1360 let host_response_offset = FbsHostResponse::create(
1361 &mut builder,
1362 &HostResponseArgs {
1363 response_type: HostResponseType::ContractResponse,
1364 response: Some(put_response_offset.as_union_value()),
1365 },
1366 );
1367
1368 finish_host_response_buffer(&mut builder, host_response_offset);
1369 Ok(builder.finished_data().to_vec())
1370 }
1371 ContractResponse::SubscribeResponse { .. } => todo!(),
1372 ContractResponse::NotFound { instance_id } => {
1373 let instance_data = builder.create_vector(instance_id.as_bytes());
1374 let instance_offset = FbsContractInstanceId::create(
1375 &mut builder,
1376 &ContractInstanceIdArgs {
1377 data: Some(instance_data),
1378 },
1379 );
1380
1381 let not_found_offset = FbsNotFound::create(
1382 &mut builder,
1383 &NotFoundArgs {
1384 instance_id: Some(instance_offset),
1385 },
1386 );
1387
1388 let contract_response_offset = FbsContractResponse::create(
1389 &mut builder,
1390 &ContractResponseArgs {
1391 contract_response_type: ContractResponseType::NotFound,
1392 contract_response: Some(not_found_offset.as_union_value()),
1393 },
1394 );
1395
1396 let response_offset = FbsHostResponse::create(
1397 &mut builder,
1398 &HostResponseArgs {
1399 response: Some(contract_response_offset.as_union_value()),
1400 response_type: HostResponseType::ContractResponse,
1401 },
1402 );
1403
1404 finish_host_response_buffer(&mut builder, response_offset);
1405 Ok(builder.finished_data().to_vec())
1406 }
1407 },
1408 HostResponse::DelegateResponse { key, values } => {
1409 let key_data = builder.create_vector(key.bytes());
1410 let code_hash_data = builder.create_vector(&key.code_hash().0);
1411 let key_offset = FbsDelegateKey::create(
1412 &mut builder,
1413 &DelegateKeyArgs {
1414 key: Some(key_data),
1415 code_hash: Some(code_hash_data),
1416 },
1417 );
1418 let mut messages: Vec<WIPOffset<FbsOutboundDelegateMsg>> = Vec::new();
1419 values.iter().for_each(|msg| match msg {
1420 OutboundDelegateMsg::ApplicationMessage(app) => {
1421 let instance_data = builder.create_vector(key.bytes());
1422 let instance_offset = FbsContractInstanceId::create(
1423 &mut builder,
1424 &ContractInstanceIdArgs {
1425 data: Some(instance_data),
1426 },
1427 );
1428 let payload_data = builder.create_vector(&app.payload);
1429 let delegate_context_data = builder.create_vector(app.context.as_ref());
1430 let app_offset = FbsApplicationMessage::create(
1431 &mut builder,
1432 &ApplicationMessageArgs {
1433 app: Some(instance_offset),
1434 payload: Some(payload_data),
1435 context: Some(delegate_context_data),
1436 processed: app.processed,
1437 },
1438 );
1439 let msg = FbsOutboundDelegateMsg::create(
1440 &mut builder,
1441 &OutboundDelegateMsgArgs {
1442 inbound_type: OutboundDelegateMsgType::common_ApplicationMessage,
1443 inbound: Some(app_offset.as_union_value()),
1444 },
1445 );
1446 messages.push(msg);
1447 }
1448 OutboundDelegateMsg::RequestUserInput(input) => {
1449 let message_data = builder.create_vector(input.message.bytes());
1450 let mut responses: Vec<WIPOffset<FbsClientResponse>> = Vec::new();
1451 input.responses.iter().for_each(|resp| {
1452 let response_data = builder.create_vector(resp.bytes());
1453 let response = FbsClientResponse::create(
1454 &mut builder,
1455 &ClientResponseArgs {
1456 data: Some(response_data),
1457 },
1458 );
1459 responses.push(response)
1460 });
1461 let responses_offset = builder.create_vector(&responses);
1462 let input_offset = FbsRequestUserInput::create(
1463 &mut builder,
1464 &RequestUserInputArgs {
1465 request_id: input.request_id,
1466 message: Some(message_data),
1467 responses: Some(responses_offset),
1468 },
1469 );
1470 let msg = FbsOutboundDelegateMsg::create(
1471 &mut builder,
1472 &OutboundDelegateMsgArgs {
1473 inbound_type: OutboundDelegateMsgType::RequestUserInput,
1474 inbound: Some(input_offset.as_union_value()),
1475 },
1476 );
1477 messages.push(msg);
1478 }
1479 OutboundDelegateMsg::ContextUpdated(context) => {
1480 let context_data = builder.create_vector(context.as_ref());
1481 let context_offset = FbsContextUpdated::create(
1482 &mut builder,
1483 &ContextUpdatedArgs {
1484 context: Some(context_data),
1485 },
1486 );
1487 let msg = FbsOutboundDelegateMsg::create(
1488 &mut builder,
1489 &OutboundDelegateMsgArgs {
1490 inbound_type: OutboundDelegateMsgType::ContextUpdated,
1491 inbound: Some(context_offset.as_union_value()),
1492 },
1493 );
1494 messages.push(msg);
1495 }
1496 OutboundDelegateMsg::GetSecretRequest(request) => {
1497 let secret_key_data = builder.create_vector(request.key.key());
1498 let secret_hash_data = builder.create_vector(request.key.hash());
1499 let secret_id_offset = FbsSecretsId::create(
1500 &mut builder,
1501 &SecretsIdArgs {
1502 key: Some(secret_key_data),
1503 hash: Some(secret_hash_data),
1504 },
1505 );
1506
1507 let delegate_context_data = builder.create_vector(request.context.as_ref());
1508 let request_offset = FbsGetSecretRequest::create(
1509 &mut builder,
1510 &GetSecretRequestArgs {
1511 key: Some(secret_id_offset),
1512 delegate_context: Some(delegate_context_data),
1513 processed: request.processed,
1514 },
1515 );
1516 let msg = FbsOutboundDelegateMsg::create(
1517 &mut builder,
1518 &OutboundDelegateMsgArgs {
1519 inbound_type: OutboundDelegateMsgType::common_GetSecretRequest,
1520 inbound: Some(request_offset.as_union_value()),
1521 },
1522 );
1523 messages.push(msg);
1524 }
1525 OutboundDelegateMsg::SetSecretRequest(request) => {
1526 let secret_key_data = builder.create_vector(request.key.key());
1527 let secret_hash_data = builder.create_vector(request.key.hash());
1528 let secret_id_offset = FbsSecretsId::create(
1529 &mut builder,
1530 &SecretsIdArgs {
1531 key: Some(secret_key_data),
1532 hash: Some(secret_hash_data),
1533 },
1534 );
1535
1536 let value_data = request
1537 .value
1538 .clone()
1539 .map(|value| builder.create_vector(value.as_slice()));
1540 let request_offset = FbsSetSecretRequest::create(
1541 &mut builder,
1542 &SetSecretRequestArgs {
1543 key: Some(secret_id_offset),
1544 value: value_data,
1545 },
1546 );
1547 let msg = FbsOutboundDelegateMsg::create(
1548 &mut builder,
1549 &OutboundDelegateMsgArgs {
1550 inbound_type: OutboundDelegateMsgType::SetSecretRequest,
1551 inbound: Some(request_offset.as_union_value()),
1552 },
1553 );
1554 messages.push(msg);
1555 }
1556 OutboundDelegateMsg::GetSecretResponse(response) => {
1557 let secret_key_data = builder.create_vector(response.key.key());
1558 let secret_hash_data = builder.create_vector(response.key.hash());
1559 let secret_id_offset = FbsSecretsId::create(
1560 &mut builder,
1561 &SecretsIdArgs {
1562 key: Some(secret_key_data),
1563 hash: Some(secret_hash_data),
1564 },
1565 );
1566
1567 let value_data = response
1568 .value
1569 .clone()
1570 .map(|value| builder.create_vector(value.as_slice()));
1571
1572 let delegate_context_data =
1573 builder.create_vector(response.context.as_ref());
1574 let response_offset = FbsGetSecretResponse::create(
1575 &mut builder,
1576 &GetSecretResponseArgs {
1577 key: Some(secret_id_offset),
1578 value: value_data,
1579 delegate_context: Some(delegate_context_data),
1580 },
1581 );
1582 let msg = FbsOutboundDelegateMsg::create(
1583 &mut builder,
1584 &OutboundDelegateMsgArgs {
1585 inbound_type: OutboundDelegateMsgType::common_GetSecretResponse,
1586 inbound: Some(response_offset.as_union_value()),
1587 },
1588 );
1589 messages.push(msg);
1590 }
1591 OutboundDelegateMsg::GetContractRequest(_) => {
1592 tracing::error!(
1595 "GetContractRequest reached client serialization - this is a bug"
1596 );
1597 }
1598 });
1599 let messages_offset = builder.create_vector(&messages);
1600 let delegate_response_offset = FbsDelegateResponse::create(
1601 &mut builder,
1602 &DelegateResponseArgs {
1603 key: Some(key_offset),
1604 values: Some(messages_offset),
1605 },
1606 );
1607 let host_response_offset = FbsHostResponse::create(
1608 &mut builder,
1609 &HostResponseArgs {
1610 response_type: HostResponseType::DelegateResponse,
1611 response: Some(delegate_response_offset.as_union_value()),
1612 },
1613 );
1614 finish_host_response_buffer(&mut builder, host_response_offset);
1615 Ok(builder.finished_data().to_vec())
1616 }
1617 HostResponse::Ok => {
1618 let ok_offset = FbsOk::create(&mut builder, &OkArgs { msg: None });
1619 let host_response_offset = FbsHostResponse::create(
1620 &mut builder,
1621 &HostResponseArgs {
1622 response_type: HostResponseType::Ok,
1623 response: Some(ok_offset.as_union_value()),
1624 },
1625 );
1626 finish_host_response_buffer(&mut builder, host_response_offset);
1627 Ok(builder.finished_data().to_vec())
1628 }
1629 HostResponse::QueryResponse(_) => unimplemented!(),
1630 }
1631 }
1632}
1633
1634impl Display for HostResponse {
1635 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1636 match self {
1637 HostResponse::ContractResponse(res) => match res {
1638 ContractResponse::PutResponse { key } => {
1639 f.write_fmt(format_args!("put response for `{key}`"))
1640 }
1641 ContractResponse::UpdateResponse { key, .. } => {
1642 f.write_fmt(format_args!("update response for `{key}`"))
1643 }
1644 ContractResponse::GetResponse { key, .. } => {
1645 f.write_fmt(format_args!("get response for `{key}`"))
1646 }
1647 ContractResponse::UpdateNotification { key, .. } => {
1648 f.write_fmt(format_args!("update notification for `{key}`"))
1649 }
1650 ContractResponse::SubscribeResponse { key, .. } => {
1651 f.write_fmt(format_args!("subscribe response for `{key}`"))
1652 }
1653 ContractResponse::NotFound { instance_id } => {
1654 f.write_fmt(format_args!("not found for `{instance_id}`"))
1655 }
1656 },
1657 HostResponse::DelegateResponse { .. } => write!(f, "delegate responses"),
1658 HostResponse::Ok => write!(f, "ok response"),
1659 HostResponse::QueryResponse(_) => write!(f, "query response"),
1660 }
1661 }
1662}
1663
1664#[derive(Clone, Serialize, Deserialize, Debug)]
1665#[non_exhaustive]
1666pub enum ContractResponse<T = WrappedState> {
1667 GetResponse {
1668 key: ContractKey,
1669 contract: Option<ContractContainer>,
1670 #[serde(bound(deserialize = "T: DeserializeOwned"))]
1671 state: T,
1672 },
1673 PutResponse {
1674 key: ContractKey,
1675 },
1676 UpdateNotification {
1678 key: ContractKey,
1679 #[serde(deserialize_with = "UpdateData::deser_update_data")]
1680 update: UpdateData<'static>,
1681 },
1682 UpdateResponse {
1684 key: ContractKey,
1685 #[serde(deserialize_with = "StateSummary::deser_state_summary")]
1686 summary: StateSummary<'static>,
1687 },
1688 SubscribeResponse {
1689 key: ContractKey,
1690 subscribed: bool,
1691 },
1692 NotFound {
1696 instance_id: ContractInstanceId,
1698 },
1699}
1700
1701impl<T> From<ContractResponse<T>> for HostResponse<T> {
1702 fn from(value: ContractResponse<T>) -> HostResponse<T> {
1703 HostResponse::ContractResponse(value)
1704 }
1705}
1706
1707#[cfg(test)]
1708mod client_request_test {
1709 use crate::client_api::{ContractRequest, TryFromFbs};
1710 use crate::contract_interface::UpdateData;
1711 use crate::generated::client_request::root_as_client_request;
1712
1713 const EXPECTED_ENCODED_CONTRACT_ID: &str = "6kVs66bKaQAC6ohr8b43SvJ95r36tc2hnG7HezmaJHF9";
1714
1715 #[test]
1716 fn test_build_contract_put_op_from_fbs() -> Result<(), Box<dyn std::error::Error>> {
1717 let put_req_op = vec![
1718 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,
1719 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,
1720 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,
1721 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,
1722 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,
1723 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,
1724 85, 111, 11, 171, 40, 85, 240, 177, 207, 81, 106, 157, 173, 90, 234, 2, 250, 253, 75,
1725 210, 62, 7, 6, 34, 75, 26, 229, 230, 107, 167, 17, 108, 8, 0, 0, 0, 1, 2, 3, 4, 5, 6,
1726 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,
1727 3, 4, 5, 6, 7, 8, 8, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8,
1728 ];
1729 let request = if let Ok(client_request) = root_as_client_request(&put_req_op) {
1730 let contract_request = client_request.client_request_as_contract_request().unwrap();
1731 ContractRequest::try_decode_fbs(&contract_request)?
1732 } else {
1733 panic!("failed to decode client request")
1734 };
1735
1736 match request {
1737 ContractRequest::Put {
1738 contract,
1739 state,
1740 related_contracts: _,
1741 subscribe,
1742 blocking_subscribe,
1743 } => {
1744 assert_eq!(
1745 contract.to_string(),
1746 "WasmContainer([api=0.0.1](D8fdVLbRyMLw5mZtPRpWMFcrXGN2z8Nq8UGcLGPFBg2W))"
1747 );
1748 assert_eq!(contract.unwrap_v1().data.data(), &[1, 2, 3, 4, 5, 6, 7, 8]);
1749 assert_eq!(state.to_vec(), &[1, 2, 3, 4, 5, 6, 7, 8]);
1750 assert!(!subscribe);
1751 assert!(!blocking_subscribe);
1752 }
1753 _ => panic!("wrong contract request type"),
1754 }
1755
1756 Ok(())
1757 }
1758
1759 #[test]
1760 fn test_build_contract_get_op_from_fbs() -> Result<(), Box<dyn std::error::Error>> {
1761 let get_req_op = vec![
1762 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,
1763 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,
1764 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,
1765 4, 0, 0, 0, 32, 0, 0, 0, 85, 111, 11, 171, 40, 85, 240, 177, 207, 81, 106, 157, 173,
1766 90, 234, 2, 250, 253, 75, 210, 62, 7, 6, 34, 75, 26, 229, 230, 107, 167, 17, 108,
1767 ];
1768 let request = if let Ok(client_request) = root_as_client_request(&get_req_op) {
1769 let contract_request = client_request.client_request_as_contract_request().unwrap();
1770 ContractRequest::try_decode_fbs(&contract_request)?
1771 } else {
1772 panic!("failed to decode client request")
1773 };
1774
1775 match request {
1776 ContractRequest::Get {
1777 key,
1778 return_contract_code: fetch_contract,
1779 subscribe,
1780 blocking_subscribe,
1781 } => {
1782 assert_eq!(key.encode(), EXPECTED_ENCODED_CONTRACT_ID);
1783 assert!(!fetch_contract);
1784 assert!(!subscribe);
1785 assert!(!blocking_subscribe);
1786 }
1787 _ => panic!("wrong contract request type"),
1788 }
1789
1790 Ok(())
1791 }
1792
1793 #[test]
1794 fn test_build_contract_update_op_from_fbs() -> Result<(), Box<dyn std::error::Error>> {
1795 let update_op = vec![
1796 4, 0, 0, 0, 220, 255, 255, 255, 8, 0, 0, 0, 0, 0, 0, 1, 232, 255, 255, 255, 8, 0, 0, 0,
1797 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,
1798 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,
1799 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,
1800 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,
1801 85, 240, 177, 207, 81, 106, 157, 173, 90, 234, 2, 250, 253, 75, 210, 62, 7, 6, 34, 75,
1802 26, 229, 230, 107, 167, 17, 108,
1803 ];
1804 let request = if let Ok(client_request) = root_as_client_request(&update_op) {
1805 let contract_request = client_request.client_request_as_contract_request().unwrap();
1806 ContractRequest::try_decode_fbs(&contract_request)?
1807 } else {
1808 panic!("failed to decode client request")
1809 };
1810
1811 match request {
1812 ContractRequest::Update { key, data } => {
1813 assert_eq!(
1814 key.encoded_contract_id(),
1815 "6kVs66bKaQAC6ohr8b43SvJ95r36tc2hnG7HezmaJHF9"
1816 );
1817 match data {
1818 UpdateData::Delta(delta) => {
1819 assert_eq!(delta.to_vec(), &[1, 2, 3, 4, 5, 6, 7, 8])
1820 }
1821 _ => panic!("wrong update data type"),
1822 }
1823 }
1824 _ => panic!("wrong contract request type"),
1825 }
1826
1827 Ok(())
1828 }
1829}