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 = key
962 .code_hash()
963 .map(|code| builder.create_vector(code.0.as_ref()));
964 let key_offset = FbsContractKey::create(
965 &mut builder,
966 &ContractKeyArgs {
967 instance: Some(instance_offset),
968 code,
969 },
970 );
971
972 let put_offset = FbsPutResponse::create(
973 &mut builder,
974 &PutResponseArgs {
975 key: Some(key_offset),
976 },
977 );
978
979 let contract_response_offset = FbsContractResponse::create(
980 &mut builder,
981 &ContractResponseArgs {
982 contract_response: Some(put_offset.as_union_value()),
983 contract_response_type: ContractResponseType::PutResponse,
984 },
985 );
986
987 let response_offset = FbsHostResponse::create(
988 &mut builder,
989 &HostResponseArgs {
990 response: Some(contract_response_offset.as_union_value()),
991 response_type: HostResponseType::ContractResponse,
992 },
993 );
994
995 finish_host_response_buffer(&mut builder, response_offset);
996 Ok(builder.finished_data().to_vec())
997 }
998 ContractResponse::UpdateResponse { key, summary } => {
999 let instance_data = builder.create_vector(key.as_bytes());
1000 let instance_offset = ContractInstanceId::create(
1001 &mut builder,
1002 &ContractInstanceIdArgs {
1003 data: Some(instance_data),
1004 },
1005 );
1006
1007 let code = key
1008 .code_hash()
1009 .map(|code| builder.create_vector(code.0.as_ref()));
1010
1011 let key_offset = FbsContractKey::create(
1012 &mut builder,
1013 &ContractKeyArgs {
1014 instance: Some(instance_offset),
1015 code,
1016 },
1017 );
1018
1019 let summary_data = builder.create_vector(&summary.into_bytes());
1020
1021 let update_response_offset = FbsUpdateResponse::create(
1022 &mut builder,
1023 &UpdateResponseArgs {
1024 key: Some(key_offset),
1025 summary: Some(summary_data),
1026 },
1027 );
1028
1029 let contract_response_offset = FbsContractResponse::create(
1030 &mut builder,
1031 &ContractResponseArgs {
1032 contract_response: Some(update_response_offset.as_union_value()),
1033 contract_response_type: ContractResponseType::UpdateResponse,
1034 },
1035 );
1036
1037 let response_offset = FbsHostResponse::create(
1038 &mut builder,
1039 &HostResponseArgs {
1040 response: Some(contract_response_offset.as_union_value()),
1041 response_type: HostResponseType::ContractResponse,
1042 },
1043 );
1044
1045 finish_host_response_buffer(&mut builder, response_offset);
1046 Ok(builder.finished_data().to_vec())
1047 }
1048 ContractResponse::GetResponse {
1049 key,
1050 contract: contract_container,
1051 state,
1052 } => {
1053 let instance_data = builder.create_vector(key.as_bytes());
1054 let instance_offset = ContractInstanceId::create(
1055 &mut builder,
1056 &ContractInstanceIdArgs {
1057 data: Some(instance_data),
1058 },
1059 );
1060
1061 let code = key.code_hash().map(|code| builder.create_vector(&code.0));
1062 let key_offset = FbsContractKey::create(
1063 &mut builder,
1064 &ContractKeyArgs {
1065 instance: Some(instance_offset),
1066 code,
1067 },
1068 );
1069
1070 let container_offset = if let Some(contract) = contract_container {
1071 let data = builder.create_vector(contract.key().as_bytes());
1072
1073 let instance_offset = ContractInstanceId::create(
1074 &mut builder,
1075 &ContractInstanceIdArgs { data: Some(data) },
1076 );
1077
1078 let code = contract
1079 .key()
1080 .code_hash()
1081 .map(|code| builder.create_vector(&code.0));
1082 let contract_key_offset = FbsContractKey::create(
1083 &mut builder,
1084 &ContractKeyArgs {
1085 instance: Some(instance_offset),
1086 code,
1087 },
1088 );
1089
1090 let contract_data =
1091 builder.create_vector(contract.clone().unwrap_v1().data.data());
1092 let contract_code_hash =
1093 builder.create_vector(&contract.clone().unwrap_v1().data.hash().0);
1094
1095 let contract_code_offset = ContractCode::create(
1096 &mut builder,
1097 &ContractCodeArgs {
1098 data: Some(contract_data),
1099 code_hash: Some(contract_code_hash),
1100 },
1101 );
1102
1103 let contract_params =
1104 builder.create_vector(&contract.clone().params().into_bytes());
1105
1106 let contract_offset = match contract {
1107 Wasm(V1(..)) => WasmContractV1::create(
1108 &mut builder,
1109 &WasmContractV1Args {
1110 key: Some(contract_key_offset),
1111 data: Some(contract_code_offset),
1112 parameters: Some(contract_params),
1113 },
1114 ),
1115 };
1116
1117 Some(FbsContractContainer::create(
1118 &mut builder,
1119 &ContractContainerArgs {
1120 contract_type: ContractType::WasmContractV1,
1121 contract: Some(contract_offset.as_union_value()),
1122 },
1123 ))
1124 } else {
1125 None
1126 };
1127
1128 let state_data = builder.create_vector(&state);
1129
1130 let get_offset = FbsGetResponse::create(
1131 &mut builder,
1132 &GetResponseArgs {
1133 key: Some(key_offset),
1134 contract: container_offset,
1135 state: Some(state_data),
1136 },
1137 );
1138
1139 let contract_response_offset = FbsContractResponse::create(
1140 &mut builder,
1141 &ContractResponseArgs {
1142 contract_response_type: ContractResponseType::GetResponse,
1143 contract_response: Some(get_offset.as_union_value()),
1144 },
1145 );
1146
1147 let response_offset = FbsHostResponse::create(
1148 &mut builder,
1149 &HostResponseArgs {
1150 response: Some(contract_response_offset.as_union_value()),
1151 response_type: HostResponseType::ContractResponse,
1152 },
1153 );
1154
1155 finish_host_response_buffer(&mut builder, response_offset);
1156 Ok(builder.finished_data().to_vec())
1157 }
1158 ContractResponse::UpdateNotification { key, update } => {
1159 let instance_data = builder.create_vector(key.as_bytes());
1160 let instance_offset = ContractInstanceId::create(
1161 &mut builder,
1162 &ContractInstanceIdArgs {
1163 data: Some(instance_data),
1164 },
1165 );
1166
1167 let code = key
1168 .code_hash()
1169 .map(|code| builder.create_vector(code.0.as_ref()));
1170 let key_offset = FbsContractKey::create(
1171 &mut builder,
1172 &ContractKeyArgs {
1173 instance: Some(instance_offset),
1174 code,
1175 },
1176 );
1177
1178 let update_data = match update {
1179 State(state) => {
1180 let state_data = builder.create_vector(&state.into_bytes());
1181 let state_update_offset = StateUpdate::create(
1182 &mut builder,
1183 &StateUpdateArgs {
1184 state: Some(state_data),
1185 },
1186 );
1187 FbsUpdateData::create(
1188 &mut builder,
1189 &UpdateDataArgs {
1190 update_data_type: UpdateDataType::StateUpdate,
1191 update_data: Some(state_update_offset.as_union_value()),
1192 },
1193 )
1194 }
1195 Delta(delta) => {
1196 let delta_data = builder.create_vector(&delta.into_bytes());
1197 let update_offset = DeltaUpdate::create(
1198 &mut builder,
1199 &DeltaUpdateArgs {
1200 delta: Some(delta_data),
1201 },
1202 );
1203 FbsUpdateData::create(
1204 &mut builder,
1205 &UpdateDataArgs {
1206 update_data_type: UpdateDataType::DeltaUpdate,
1207 update_data: Some(update_offset.as_union_value()),
1208 },
1209 )
1210 }
1211 StateAndDelta { state, delta } => {
1212 let state_data = builder.create_vector(&state.into_bytes());
1213 let delta_data = builder.create_vector(&delta.into_bytes());
1214
1215 let update_offset = StateAndDeltaUpdate::create(
1216 &mut builder,
1217 &StateAndDeltaUpdateArgs {
1218 state: Some(state_data),
1219 delta: Some(delta_data),
1220 },
1221 );
1222
1223 FbsUpdateData::create(
1224 &mut builder,
1225 &UpdateDataArgs {
1226 update_data_type: UpdateDataType::StateAndDeltaUpdate,
1227 update_data: Some(update_offset.as_union_value()),
1228 },
1229 )
1230 }
1231 RelatedState { related_to, state } => {
1232 let state_data = builder.create_vector(&state.into_bytes());
1233 let instance_data =
1234 builder.create_vector(related_to.encode().as_bytes());
1235
1236 let instance_offset = ContractInstanceId::create(
1237 &mut builder,
1238 &ContractInstanceIdArgs {
1239 data: Some(instance_data),
1240 },
1241 );
1242
1243 let update_offset = RelatedStateUpdate::create(
1244 &mut builder,
1245 &RelatedStateUpdateArgs {
1246 related_to: Some(instance_offset),
1247 state: Some(state_data),
1248 },
1249 );
1250
1251 FbsUpdateData::create(
1252 &mut builder,
1253 &UpdateDataArgs {
1254 update_data_type: UpdateDataType::RelatedStateUpdate,
1255 update_data: Some(update_offset.as_union_value()),
1256 },
1257 )
1258 }
1259 RelatedDelta { related_to, delta } => {
1260 let instance_data =
1261 builder.create_vector(related_to.encode().as_bytes());
1262 let delta_data = builder.create_vector(&delta.into_bytes());
1263
1264 let instance_offset = ContractInstanceId::create(
1265 &mut builder,
1266 &ContractInstanceIdArgs {
1267 data: Some(instance_data),
1268 },
1269 );
1270
1271 let update_offset = RelatedDeltaUpdate::create(
1272 &mut builder,
1273 &RelatedDeltaUpdateArgs {
1274 related_to: Some(instance_offset),
1275 delta: Some(delta_data),
1276 },
1277 );
1278
1279 FbsUpdateData::create(
1280 &mut builder,
1281 &UpdateDataArgs {
1282 update_data_type: UpdateDataType::RelatedDeltaUpdate,
1283 update_data: Some(update_offset.as_union_value()),
1284 },
1285 )
1286 }
1287 RelatedStateAndDelta {
1288 related_to,
1289 state,
1290 delta,
1291 } => {
1292 let instance_data =
1293 builder.create_vector(related_to.encode().as_bytes());
1294 let state_data = builder.create_vector(&state.into_bytes());
1295 let delta_data = builder.create_vector(&delta.into_bytes());
1296
1297 let instance_offset = ContractInstanceId::create(
1298 &mut builder,
1299 &ContractInstanceIdArgs {
1300 data: Some(instance_data),
1301 },
1302 );
1303
1304 let update_offset = RelatedStateAndDeltaUpdate::create(
1305 &mut builder,
1306 &RelatedStateAndDeltaUpdateArgs {
1307 related_to: Some(instance_offset),
1308 state: Some(state_data),
1309 delta: Some(delta_data),
1310 },
1311 );
1312
1313 FbsUpdateData::create(
1314 &mut builder,
1315 &UpdateDataArgs {
1316 update_data_type: UpdateDataType::RelatedStateAndDeltaUpdate,
1317 update_data: Some(update_offset.as_union_value()),
1318 },
1319 )
1320 }
1321 };
1322
1323 let update_notification_offset = FbsUpdateNotification::create(
1324 &mut builder,
1325 &UpdateNotificationArgs {
1326 key: Some(key_offset),
1327 update: Some(update_data),
1328 },
1329 );
1330
1331 let put_response_offset = FbsContractResponse::create(
1332 &mut builder,
1333 &ContractResponseArgs {
1334 contract_response_type: ContractResponseType::UpdateNotification,
1335 contract_response: Some(update_notification_offset.as_union_value()),
1336 },
1337 );
1338
1339 let host_response_offset = FbsHostResponse::create(
1340 &mut builder,
1341 &HostResponseArgs {
1342 response_type: HostResponseType::ContractResponse,
1343 response: Some(put_response_offset.as_union_value()),
1344 },
1345 );
1346
1347 finish_host_response_buffer(&mut builder, host_response_offset);
1348 Ok(builder.finished_data().to_vec())
1349 }
1350 ContractResponse::SubscribeResponse { .. } => todo!(),
1351 },
1352 HostResponse::DelegateResponse { key, values } => {
1353 let key_data = builder.create_vector(key.bytes());
1354 let code_hash_data = builder.create_vector(&key.code_hash().0);
1355 let key_offset = FbsDelegateKey::create(
1356 &mut builder,
1357 &DelegateKeyArgs {
1358 key: Some(key_data),
1359 code_hash: Some(code_hash_data),
1360 },
1361 );
1362 let mut messages: Vec<WIPOffset<FbsOutboundDelegateMsg>> = Vec::new();
1363 values.iter().for_each(|msg| match msg {
1364 OutboundDelegateMsg::ApplicationMessage(app) => {
1365 let instance_data = builder.create_vector(key.bytes());
1366 let instance_offset = ContractInstanceId::create(
1367 &mut builder,
1368 &ContractInstanceIdArgs {
1369 data: Some(instance_data),
1370 },
1371 );
1372 let payload_data = builder.create_vector(&app.payload);
1373 let delegate_context_data = builder.create_vector(app.context.as_ref());
1374 let app_offset = FbsApplicationMessage::create(
1375 &mut builder,
1376 &ApplicationMessageArgs {
1377 app: Some(instance_offset),
1378 payload: Some(payload_data),
1379 context: Some(delegate_context_data),
1380 processed: app.processed,
1381 },
1382 );
1383 let msg = FbsOutboundDelegateMsg::create(
1384 &mut builder,
1385 &OutboundDelegateMsgArgs {
1386 inbound_type: OutboundDelegateMsgType::common_ApplicationMessage,
1387 inbound: Some(app_offset.as_union_value()),
1388 },
1389 );
1390 messages.push(msg);
1391 }
1392 OutboundDelegateMsg::RequestUserInput(input) => {
1393 let message_data = builder.create_vector(input.message.bytes());
1394 let mut responses: Vec<WIPOffset<FbsClientResponse>> = Vec::new();
1395 input.responses.iter().for_each(|resp| {
1396 let response_data = builder.create_vector(resp.bytes());
1397 let response = FbsClientResponse::create(
1398 &mut builder,
1399 &ClientResponseArgs {
1400 data: Some(response_data),
1401 },
1402 );
1403 responses.push(response)
1404 });
1405 let responses_offset = builder.create_vector(&responses);
1406 let input_offset = FbsRequestUserInput::create(
1407 &mut builder,
1408 &RequestUserInputArgs {
1409 request_id: input.request_id,
1410 message: Some(message_data),
1411 responses: Some(responses_offset),
1412 },
1413 );
1414 let msg = FbsOutboundDelegateMsg::create(
1415 &mut builder,
1416 &OutboundDelegateMsgArgs {
1417 inbound_type: OutboundDelegateMsgType::RequestUserInput,
1418 inbound: Some(input_offset.as_union_value()),
1419 },
1420 );
1421 messages.push(msg);
1422 }
1423 OutboundDelegateMsg::ContextUpdated(context) => {
1424 let context_data = builder.create_vector(context.as_ref());
1425 let context_offset = FbsContextUpdated::create(
1426 &mut builder,
1427 &ContextUpdatedArgs {
1428 context: Some(context_data),
1429 },
1430 );
1431 let msg = FbsOutboundDelegateMsg::create(
1432 &mut builder,
1433 &OutboundDelegateMsgArgs {
1434 inbound_type: OutboundDelegateMsgType::ContextUpdated,
1435 inbound: Some(context_offset.as_union_value()),
1436 },
1437 );
1438 messages.push(msg);
1439 }
1440 OutboundDelegateMsg::GetSecretRequest(request) => {
1441 let secret_key_data = builder.create_vector(request.key.key());
1442 let secret_hash_data = builder.create_vector(request.key.hash());
1443 let secret_id_offset = FbsSecretsId::create(
1444 &mut builder,
1445 &SecretsIdArgs {
1446 key: Some(secret_key_data),
1447 hash: Some(secret_hash_data),
1448 },
1449 );
1450
1451 let delegate_context_data = builder.create_vector(request.context.as_ref());
1452 let request_offset = FbsGetSecretRequest::create(
1453 &mut builder,
1454 &GetSecretRequestArgs {
1455 key: Some(secret_id_offset),
1456 delegate_context: Some(delegate_context_data),
1457 processed: request.processed,
1458 },
1459 );
1460 let msg = FbsOutboundDelegateMsg::create(
1461 &mut builder,
1462 &OutboundDelegateMsgArgs {
1463 inbound_type: OutboundDelegateMsgType::common_GetSecretRequest,
1464 inbound: Some(request_offset.as_union_value()),
1465 },
1466 );
1467 messages.push(msg);
1468 }
1469 OutboundDelegateMsg::SetSecretRequest(request) => {
1470 let secret_key_data = builder.create_vector(request.key.key());
1471 let secret_hash_data = builder.create_vector(request.key.hash());
1472 let secret_id_offset = FbsSecretsId::create(
1473 &mut builder,
1474 &SecretsIdArgs {
1475 key: Some(secret_key_data),
1476 hash: Some(secret_hash_data),
1477 },
1478 );
1479
1480 let value_data = request
1481 .value
1482 .clone()
1483 .map(|value| builder.create_vector(value.as_slice()));
1484 let request_offset = FbsSetSecretRequest::create(
1485 &mut builder,
1486 &SetSecretRequestArgs {
1487 key: Some(secret_id_offset),
1488 value: value_data,
1489 },
1490 );
1491 let msg = FbsOutboundDelegateMsg::create(
1492 &mut builder,
1493 &OutboundDelegateMsgArgs {
1494 inbound_type: OutboundDelegateMsgType::SetSecretRequest,
1495 inbound: Some(request_offset.as_union_value()),
1496 },
1497 );
1498 messages.push(msg);
1499 }
1500 OutboundDelegateMsg::GetSecretResponse(response) => {
1501 let secret_key_data = builder.create_vector(response.key.key());
1502 let secret_hash_data = builder.create_vector(response.key.hash());
1503 let secret_id_offset = FbsSecretsId::create(
1504 &mut builder,
1505 &SecretsIdArgs {
1506 key: Some(secret_key_data),
1507 hash: Some(secret_hash_data),
1508 },
1509 );
1510
1511 let value_data = response
1512 .value
1513 .clone()
1514 .map(|value| builder.create_vector(value.as_slice()));
1515
1516 let delegate_context_data =
1517 builder.create_vector(response.context.as_ref());
1518 let response_offset = FbsGetSecretResponse::create(
1519 &mut builder,
1520 &GetSecretResponseArgs {
1521 key: Some(secret_id_offset),
1522 value: value_data,
1523 delegate_context: Some(delegate_context_data),
1524 },
1525 );
1526 let msg = FbsOutboundDelegateMsg::create(
1527 &mut builder,
1528 &OutboundDelegateMsgArgs {
1529 inbound_type: OutboundDelegateMsgType::common_GetSecretResponse,
1530 inbound: Some(response_offset.as_union_value()),
1531 },
1532 );
1533 messages.push(msg);
1534 }
1535 });
1536 let messages_offset = builder.create_vector(&messages);
1537 let delegate_response_offset = FbsDelegateResponse::create(
1538 &mut builder,
1539 &DelegateResponseArgs {
1540 key: Some(key_offset),
1541 values: Some(messages_offset),
1542 },
1543 );
1544 let host_response_offset = FbsHostResponse::create(
1545 &mut builder,
1546 &HostResponseArgs {
1547 response_type: HostResponseType::DelegateResponse,
1548 response: Some(delegate_response_offset.as_union_value()),
1549 },
1550 );
1551 finish_host_response_buffer(&mut builder, host_response_offset);
1552 Ok(builder.finished_data().to_vec())
1553 }
1554 HostResponse::Ok => {
1555 let ok_offset = FbsOk::create(&mut builder, &OkArgs { msg: None });
1556 let host_response_offset = FbsHostResponse::create(
1557 &mut builder,
1558 &HostResponseArgs {
1559 response_type: HostResponseType::Ok,
1560 response: Some(ok_offset.as_union_value()),
1561 },
1562 );
1563 finish_host_response_buffer(&mut builder, host_response_offset);
1564 Ok(builder.finished_data().to_vec())
1565 }
1566 HostResponse::QueryResponse(_) => unimplemented!(),
1567 }
1568 }
1569}
1570
1571impl Display for HostResponse {
1572 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1573 match self {
1574 HostResponse::ContractResponse(res) => match res {
1575 ContractResponse::PutResponse { key } => {
1576 f.write_fmt(format_args!("put response for `{key}`"))
1577 }
1578 ContractResponse::UpdateResponse { key, .. } => {
1579 f.write_fmt(format_args!("update response for `{key}`"))
1580 }
1581 ContractResponse::GetResponse { key, .. } => {
1582 f.write_fmt(format_args!("get response for `{key}`"))
1583 }
1584 ContractResponse::UpdateNotification { key, .. } => {
1585 f.write_fmt(format_args!("update notification for `{key}`"))
1586 }
1587 ContractResponse::SubscribeResponse { key, .. } => {
1588 f.write_fmt(format_args!("subscribe response for `{key}`"))
1589 }
1590 },
1591 HostResponse::DelegateResponse { .. } => write!(f, "delegate responses"),
1592 HostResponse::Ok => write!(f, "ok response"),
1593 HostResponse::QueryResponse(_) => write!(f, "query response"),
1594 }
1595 }
1596}
1597
1598#[derive(Clone, Serialize, Deserialize, Debug)]
1599#[non_exhaustive]
1600pub enum ContractResponse<T = WrappedState> {
1601 GetResponse {
1602 key: ContractKey,
1603 contract: Option<ContractContainer>,
1604 #[serde(bound(deserialize = "T: DeserializeOwned"))]
1605 state: T,
1606 },
1607 PutResponse {
1608 key: ContractKey,
1609 },
1610 UpdateNotification {
1612 key: ContractKey,
1613 #[serde(deserialize_with = "UpdateData::deser_update_data")]
1614 update: UpdateData<'static>,
1615 },
1616 UpdateResponse {
1618 key: ContractKey,
1619 #[serde(deserialize_with = "StateSummary::deser_state_summary")]
1620 summary: StateSummary<'static>,
1621 },
1622 SubscribeResponse {
1623 key: ContractKey,
1624 subscribed: bool,
1625 },
1626}
1627
1628impl<T> From<ContractResponse<T>> for HostResponse<T> {
1629 fn from(value: ContractResponse<T>) -> HostResponse<T> {
1630 HostResponse::ContractResponse(value)
1631 }
1632}
1633
1634#[cfg(test)]
1635mod client_request_test {
1636 use crate::client_api::{ContractRequest, TryFromFbs};
1637 use crate::contract_interface::UpdateData;
1638 use crate::generated::client_request::root_as_client_request;
1639
1640 const EXPECTED_ENCODED_CONTRACT_ID: &str = "6kVs66bKaQAC6ohr8b43SvJ95r36tc2hnG7HezmaJHF9";
1641
1642 #[test]
1643 fn test_build_contract_put_op_from_fbs() -> Result<(), Box<dyn std::error::Error>> {
1644 let put_req_op = vec![
1645 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,
1646 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,
1647 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,
1648 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,
1649 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,
1650 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,
1651 85, 111, 11, 171, 40, 85, 240, 177, 207, 81, 106, 157, 173, 90, 234, 2, 250, 253, 75,
1652 210, 62, 7, 6, 34, 75, 26, 229, 230, 107, 167, 17, 108, 8, 0, 0, 0, 1, 2, 3, 4, 5, 6,
1653 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,
1654 3, 4, 5, 6, 7, 8, 8, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8,
1655 ];
1656 let request = if let Ok(client_request) = root_as_client_request(&put_req_op) {
1657 let contract_request = client_request.client_request_as_contract_request().unwrap();
1658 ContractRequest::try_decode_fbs(&contract_request)?
1659 } else {
1660 panic!("failed to decode client request")
1661 };
1662
1663 match request {
1664 ContractRequest::Put {
1665 contract,
1666 state,
1667 related_contracts: _,
1668 subscribe,
1669 } => {
1670 assert_eq!(
1671 contract.to_string(),
1672 "WasmContainer([api=0.0.1](D8fdVLbRyMLw5mZtPRpWMFcrXGN2z8Nq8UGcLGPFBg2W))"
1673 );
1674 assert_eq!(contract.unwrap_v1().data.data(), &[1, 2, 3, 4, 5, 6, 7, 8]);
1675 assert_eq!(state.to_vec(), &[1, 2, 3, 4, 5, 6, 7, 8]);
1676 assert!(!subscribe);
1677 }
1678 _ => panic!("wrong contract request type"),
1679 }
1680
1681 Ok(())
1682 }
1683
1684 #[test]
1685 fn test_build_contract_get_op_from_fbs() -> Result<(), Box<dyn std::error::Error>> {
1686 let get_req_op = vec![
1687 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,
1688 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,
1689 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,
1690 4, 0, 0, 0, 32, 0, 0, 0, 85, 111, 11, 171, 40, 85, 240, 177, 207, 81, 106, 157, 173,
1691 90, 234, 2, 250, 253, 75, 210, 62, 7, 6, 34, 75, 26, 229, 230, 107, 167, 17, 108,
1692 ];
1693 let request = if let Ok(client_request) = root_as_client_request(&get_req_op) {
1694 let contract_request = client_request.client_request_as_contract_request().unwrap();
1695 ContractRequest::try_decode_fbs(&contract_request)?
1696 } else {
1697 panic!("failed to decode client request")
1698 };
1699
1700 match request {
1701 ContractRequest::Get {
1702 key,
1703 return_contract_code: fetch_contract,
1704 subscribe,
1705 } => {
1706 assert_eq!(key.encoded_contract_id(), EXPECTED_ENCODED_CONTRACT_ID);
1707 assert!(!fetch_contract);
1708 assert!(!subscribe);
1709 }
1710 _ => panic!("wrong contract request type"),
1711 }
1712
1713 Ok(())
1714 }
1715
1716 #[test]
1717 fn test_build_contract_update_op_from_fbs() -> Result<(), Box<dyn std::error::Error>> {
1718 let update_op = vec![
1719 4, 0, 0, 0, 220, 255, 255, 255, 8, 0, 0, 0, 0, 0, 0, 1, 232, 255, 255, 255, 8, 0, 0, 0,
1720 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,
1721 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,
1722 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,
1723 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,
1724 85, 240, 177, 207, 81, 106, 157, 173, 90, 234, 2, 250, 253, 75, 210, 62, 7, 6, 34, 75,
1725 26, 229, 230, 107, 167, 17, 108,
1726 ];
1727 let request = if let Ok(client_request) = root_as_client_request(&update_op) {
1728 let contract_request = client_request.client_request_as_contract_request().unwrap();
1729 ContractRequest::try_decode_fbs(&contract_request)?
1730 } else {
1731 panic!("failed to decode client request")
1732 };
1733
1734 match request {
1735 ContractRequest::Update { key, data } => {
1736 assert_eq!(
1737 key.encoded_contract_id(),
1738 "6kVs66bKaQAC6ohr8b43SvJ95r36tc2hnG7HezmaJHF9"
1739 );
1740 match data {
1741 UpdateData::Delta(delta) => {
1742 assert_eq!(delta.to_vec(), &[1, 2, 3, 4, 5, 6, 7, 8])
1743 }
1744 _ => panic!("wrong update data type"),
1745 }
1746 }
1747 _ => panic!("wrong contract request type"),
1748 }
1749
1750 Ok(())
1751 }
1752}