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