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