1use flatbuffers::WIPOffset;
2use std::borrow::Cow;
3use std::fmt::Display;
4use std::net::SocketAddr;
5
6use serde::{de::DeserializeOwned, Deserialize, Serialize};
7
8use crate::client_api::TryFromFbs;
9use crate::generated::client_request::{
10 root_as_client_request, ClientRequestType, ContractRequest as FbsContractRequest,
11 ContractRequestType, DelegateRequest as FbsDelegateRequest, DelegateRequestType,
12};
13
14use crate::delegate_interface::DelegateContext;
15use crate::generated::common::{
16 ApplicationMessage as FbsApplicationMessage, ApplicationMessageArgs, ContractCode,
17 ContractCodeArgs, ContractContainer as FbsContractContainer, ContractContainerArgs,
18 ContractInstanceId, ContractInstanceIdArgs, ContractKey as FbsContractKey, ContractKeyArgs,
19 ContractType, DeltaUpdate, DeltaUpdateArgs, GetSecretRequest as FbsGetSecretRequest,
20 GetSecretRequestArgs, GetSecretResponse as FbsGetSecretResponse, GetSecretResponseArgs,
21 RelatedDeltaUpdate, RelatedDeltaUpdateArgs, RelatedStateAndDeltaUpdate,
22 RelatedStateAndDeltaUpdateArgs, RelatedStateUpdate, RelatedStateUpdateArgs,
23 SecretsId as FbsSecretsId, SecretsIdArgs, StateAndDeltaUpdate, StateAndDeltaUpdateArgs,
24 StateUpdate, StateUpdateArgs, UpdateData as FbsUpdateData, UpdateDataArgs, UpdateDataType,
25 WasmContractV1, WasmContractV1Args,
26};
27use crate::generated::host_response::{
28 finish_host_response_buffer, ClientResponse as FbsClientResponse, ClientResponseArgs,
29 ContextUpdated as FbsContextUpdated, ContextUpdatedArgs,
30 ContractResponse as FbsContractResponse, ContractResponseArgs, ContractResponseType,
31 DelegateKey as FbsDelegateKey, DelegateKeyArgs, DelegateResponse as FbsDelegateResponse,
32 DelegateResponseArgs, GetResponse as FbsGetResponse, GetResponseArgs,
33 HostResponse as FbsHostResponse, HostResponseArgs, HostResponseType, Ok as FbsOk, OkArgs,
34 OutboundDelegateMsg as FbsOutboundDelegateMsg, OutboundDelegateMsgArgs,
35 OutboundDelegateMsgType, PutResponse as FbsPutResponse, PutResponseArgs,
36 RequestUserInput as FbsRequestUserInput, RequestUserInputArgs,
37 SetSecretRequest as FbsSetSecretRequest, SetSecretRequestArgs,
38 UpdateNotification as FbsUpdateNotification, UpdateNotificationArgs,
39 UpdateResponse as FbsUpdateResponse, UpdateResponseArgs,
40};
41use crate::prelude::ContractContainer::Wasm;
42use crate::prelude::ContractWasmAPIVersion::V1;
43use crate::prelude::UpdateData::{
44 Delta, RelatedDelta, RelatedState, RelatedStateAndDelta, State, StateAndDelta,
45};
46use crate::{
47 delegate_interface::{DelegateKey, InboundDelegateMsg, OutboundDelegateMsg},
48 prelude::{
49 ContractKey, DelegateContainer, GetSecretRequest, Parameters, RelatedContracts, SecretsId,
50 StateSummary, UpdateData, WrappedState,
51 },
52 versioning::ContractContainer,
53};
54
55use super::WsApiError;
56
57#[derive(Debug, Serialize, Deserialize)]
58pub struct ClientError {
59 kind: Box<ErrorKind>,
60}
61
62impl ClientError {
63 pub fn into_fbs_bytes(self) -> Result<Vec<u8>, Box<ClientError>> {
64 use crate::generated::host_response::{Error, ErrorArgs};
65 let mut builder = flatbuffers::FlatBufferBuilder::new();
66 let msg_offset = builder.create_string(&self.to_string());
67 let err_offset = Error::create(
68 &mut builder,
69 &ErrorArgs {
70 msg: Some(msg_offset),
71 },
72 );
73 let host_response_offset = FbsHostResponse::create(
74 &mut builder,
75 &HostResponseArgs {
76 response_type: HostResponseType::Ok,
77 response: Some(err_offset.as_union_value()),
78 },
79 );
80 finish_host_response_buffer(&mut builder, host_response_offset);
81 Ok(builder.finished_data().to_vec())
82 }
83
84 pub fn kind(&self) -> &ErrorKind {
85 &self.kind
86 }
87}
88
89impl From<ErrorKind> for ClientError {
90 fn from(kind: ErrorKind) -> Self {
91 ClientError {
92 kind: Box::new(kind),
93 }
94 }
95}
96
97impl<T: Into<Cow<'static, str>>> From<T> for ClientError {
98 fn from(cause: T) -> Self {
99 ClientError {
100 kind: Box::new(ErrorKind::Unhandled {
101 cause: cause.into(),
102 }),
103 }
104 }
105}
106
107#[derive(thiserror::Error, Debug, Serialize, Deserialize, Clone)]
108#[non_exhaustive]
109pub enum ErrorKind {
110 #[error("comm channel between client/host closed")]
111 ChannelClosed,
112 #[error("error while deserializing: {cause}")]
113 DeserializationError { cause: Cow<'static, str> },
114 #[error("client disconnected")]
115 Disconnect,
116 #[error("failed while trying to unpack state for {0}")]
117 IncorrectState(ContractKey),
118 #[error("node not available")]
119 NodeUnavailable,
120 #[error("lost the connection with the protocol handling connections")]
121 TransportProtocolDisconnect,
122 #[error("unhandled error: {cause}")]
123 Unhandled { cause: Cow<'static, str> },
124 #[error("unknown client id: {0}")]
125 UnknownClient(usize),
126 #[error(transparent)]
127 RequestError(#[from] RequestError),
128 #[error("error while executing operation in the network: {cause}")]
129 OperationError { cause: Cow<'static, str> },
130 #[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)]
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)]
726pub enum QueryResponse {
727 ConnectedPeers { peers: Vec<(Peer, SocketAddr)> },
728 NetworkDebug(NetworkDebugInfo),
729 NodeDiagnostics(NodeDiagnosticsResponse),
730}
731
732#[derive(Serialize, Deserialize, Debug, Clone)]
733pub struct NetworkDebugInfo {
734 pub subscriptions: Vec<SubscriptionInfo>,
735 pub connected_peers: Vec<(String, SocketAddr)>,
736}
737
738#[derive(Serialize, Deserialize, Debug, Clone)]
739pub struct NodeDiagnosticsResponse {
740 pub node_info: Option<NodeInfo>,
742
743 pub network_info: Option<NetworkInfo>,
745
746 pub subscriptions: Vec<SubscriptionInfo>,
748
749 pub contract_states: std::collections::HashMap<ContractKey, ContractState>,
751
752 pub system_metrics: Option<SystemMetrics>,
754
755 pub connected_peers_detailed: Vec<ConnectedPeerInfo>,
757}
758
759#[derive(Serialize, Deserialize, Debug, Clone)]
760pub struct NodeInfo {
761 pub peer_id: String,
762 pub is_gateway: bool,
763 pub location: Option<String>,
764 pub listening_address: Option<String>,
765 pub uptime_seconds: u64,
766}
767
768#[derive(Serialize, Deserialize, Debug, Clone)]
769pub struct NetworkInfo {
770 pub connected_peers: Vec<(String, String)>, pub active_connections: usize,
772}
773
774#[derive(Serialize, Deserialize, Debug, Clone)]
775pub struct ContractState {
776 pub subscribers: u32,
778 pub subscriber_peer_ids: Vec<String>,
780}
781
782#[derive(Serialize, Deserialize, Debug, Clone)]
783pub struct SystemMetrics {
784 pub active_connections: u32,
785 pub seeding_contracts: u32,
786}
787
788#[derive(Serialize, Deserialize, Debug, Clone)]
789pub struct SubscriptionInfo {
790 pub contract_key: ContractKey,
791 pub client_id: usize,
792}
793
794#[derive(Serialize, Deserialize, Debug, Clone)]
796pub struct ConnectedPeerInfo {
797 pub peer_id: String,
798 pub address: String,
799}
800
801#[derive(Serialize, Deserialize, Debug, Clone)]
802pub enum NodeQuery {
803 ConnectedPeers,
804 SubscriptionInfo,
805 NodeDiagnostics {
806 config: NodeDiagnosticsConfig,
808 },
809}
810
811#[derive(Serialize, Deserialize, Debug, Clone)]
812pub struct NodeDiagnosticsConfig {
813 pub include_node_info: bool,
815
816 pub include_network_info: bool,
818
819 pub include_subscriptions: bool,
821
822 pub contract_keys: Vec<ContractKey>,
824
825 pub include_system_metrics: bool,
827
828 pub include_detailed_peer_info: bool,
830
831 pub include_subscriber_peer_ids: bool,
833}
834
835impl NodeDiagnosticsConfig {
836 pub fn for_update_propagation_debugging(contract_key: ContractKey) -> Self {
838 Self {
839 include_node_info: true,
840 include_network_info: true,
841 include_subscriptions: true,
842 contract_keys: vec![contract_key],
843 include_system_metrics: true,
844 include_detailed_peer_info: true,
845 include_subscriber_peer_ids: true,
846 }
847 }
848
849 pub fn basic_status() -> Self {
851 Self {
852 include_node_info: true,
853 include_network_info: true,
854 include_subscriptions: false,
855 contract_keys: vec![],
856 include_system_metrics: false,
857 include_detailed_peer_info: false,
858 include_subscriber_peer_ids: false,
859 }
860 }
861
862 pub fn full() -> Self {
864 Self {
865 include_node_info: true,
866 include_network_info: true,
867 include_subscriptions: true,
868 contract_keys: vec![], include_system_metrics: true,
870 include_detailed_peer_info: true,
871 include_subscriber_peer_ids: true,
872 }
873 }
874}
875
876impl HostResponse {
877 pub fn unwrap_put(self) -> ContractKey {
878 if let Self::ContractResponse(ContractResponse::PutResponse { key }) = self {
879 key
880 } else {
881 panic!("called `HostResponse::unwrap_put()` on other than `PutResponse` value")
882 }
883 }
884
885 pub fn unwrap_get(self) -> (WrappedState, Option<ContractContainer>) {
886 if let Self::ContractResponse(ContractResponse::GetResponse {
887 contract, state, ..
888 }) = self
889 {
890 (state, contract)
891 } else {
892 panic!("called `HostResponse::unwrap_put()` on other than `PutResponse` value")
893 }
894 }
895
896 pub fn into_fbs_bytes(self) -> Result<Vec<u8>, Box<ClientError>> {
897 let mut builder = flatbuffers::FlatBufferBuilder::new();
898 match self {
899 HostResponse::ContractResponse(res) => match res {
900 ContractResponse::PutResponse { key } => {
901 let instance_data = builder.create_vector(key.as_bytes());
902 let instance_offset = ContractInstanceId::create(
903 &mut builder,
904 &ContractInstanceIdArgs {
905 data: Some(instance_data),
906 },
907 );
908
909 let code = key
910 .code_hash()
911 .map(|code| builder.create_vector(code.0.as_ref()));
912 let key_offset = FbsContractKey::create(
913 &mut builder,
914 &ContractKeyArgs {
915 instance: Some(instance_offset),
916 code,
917 },
918 );
919
920 let put_offset = FbsPutResponse::create(
921 &mut builder,
922 &PutResponseArgs {
923 key: Some(key_offset),
924 },
925 );
926
927 let contract_response_offset = FbsContractResponse::create(
928 &mut builder,
929 &ContractResponseArgs {
930 contract_response: Some(put_offset.as_union_value()),
931 contract_response_type: ContractResponseType::PutResponse,
932 },
933 );
934
935 let response_offset = FbsHostResponse::create(
936 &mut builder,
937 &HostResponseArgs {
938 response: Some(contract_response_offset.as_union_value()),
939 response_type: HostResponseType::ContractResponse,
940 },
941 );
942
943 finish_host_response_buffer(&mut builder, response_offset);
944 Ok(builder.finished_data().to_vec())
945 }
946 ContractResponse::UpdateResponse { key, summary } => {
947 let instance_data = builder.create_vector(key.as_bytes());
948 let instance_offset = ContractInstanceId::create(
949 &mut builder,
950 &ContractInstanceIdArgs {
951 data: Some(instance_data),
952 },
953 );
954
955 let code = key
956 .code_hash()
957 .map(|code| builder.create_vector(code.0.as_ref()));
958
959 let key_offset = FbsContractKey::create(
960 &mut builder,
961 &ContractKeyArgs {
962 instance: Some(instance_offset),
963 code,
964 },
965 );
966
967 let summary_data = builder.create_vector(&summary.into_bytes());
968
969 let update_response_offset = FbsUpdateResponse::create(
970 &mut builder,
971 &UpdateResponseArgs {
972 key: Some(key_offset),
973 summary: Some(summary_data),
974 },
975 );
976
977 let contract_response_offset = FbsContractResponse::create(
978 &mut builder,
979 &ContractResponseArgs {
980 contract_response: Some(update_response_offset.as_union_value()),
981 contract_response_type: ContractResponseType::UpdateResponse,
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::GetResponse {
997 key,
998 contract: contract_container,
999 state,
1000 } => {
1001 let instance_data = builder.create_vector(key.as_bytes());
1002 let instance_offset = ContractInstanceId::create(
1003 &mut builder,
1004 &ContractInstanceIdArgs {
1005 data: Some(instance_data),
1006 },
1007 );
1008
1009 let code = key.code_hash().map(|code| builder.create_vector(&code.0));
1010 let key_offset = FbsContractKey::create(
1011 &mut builder,
1012 &ContractKeyArgs {
1013 instance: Some(instance_offset),
1014 code,
1015 },
1016 );
1017
1018 let container_offset = if let Some(contract) = contract_container {
1019 let data = builder.create_vector(contract.key().as_bytes());
1020
1021 let instance_offset = ContractInstanceId::create(
1022 &mut builder,
1023 &ContractInstanceIdArgs { data: Some(data) },
1024 );
1025
1026 let code = contract
1027 .key()
1028 .code_hash()
1029 .map(|code| builder.create_vector(&code.0));
1030 let contract_key_offset = FbsContractKey::create(
1031 &mut builder,
1032 &ContractKeyArgs {
1033 instance: Some(instance_offset),
1034 code,
1035 },
1036 );
1037
1038 let contract_data =
1039 builder.create_vector(contract.clone().unwrap_v1().data.data());
1040 let contract_code_hash =
1041 builder.create_vector(&contract.clone().unwrap_v1().data.hash().0);
1042
1043 let contract_code_offset = ContractCode::create(
1044 &mut builder,
1045 &ContractCodeArgs {
1046 data: Some(contract_data),
1047 code_hash: Some(contract_code_hash),
1048 },
1049 );
1050
1051 let contract_params =
1052 builder.create_vector(&contract.clone().params().into_bytes());
1053
1054 let contract_offset = match contract {
1055 Wasm(V1(..)) => WasmContractV1::create(
1056 &mut builder,
1057 &WasmContractV1Args {
1058 key: Some(contract_key_offset),
1059 data: Some(contract_code_offset),
1060 parameters: Some(contract_params),
1061 },
1062 ),
1063 };
1064
1065 Some(FbsContractContainer::create(
1066 &mut builder,
1067 &ContractContainerArgs {
1068 contract_type: ContractType::WasmContractV1,
1069 contract: Some(contract_offset.as_union_value()),
1070 },
1071 ))
1072 } else {
1073 None
1074 };
1075
1076 let state_data = builder.create_vector(&state);
1077
1078 let get_offset = FbsGetResponse::create(
1079 &mut builder,
1080 &GetResponseArgs {
1081 key: Some(key_offset),
1082 contract: container_offset,
1083 state: Some(state_data),
1084 },
1085 );
1086
1087 let contract_response_offset = FbsContractResponse::create(
1088 &mut builder,
1089 &ContractResponseArgs {
1090 contract_response_type: ContractResponseType::GetResponse,
1091 contract_response: Some(get_offset.as_union_value()),
1092 },
1093 );
1094
1095 let response_offset = FbsHostResponse::create(
1096 &mut builder,
1097 &HostResponseArgs {
1098 response: Some(contract_response_offset.as_union_value()),
1099 response_type: HostResponseType::ContractResponse,
1100 },
1101 );
1102
1103 finish_host_response_buffer(&mut builder, response_offset);
1104 Ok(builder.finished_data().to_vec())
1105 }
1106 ContractResponse::UpdateNotification { key, update } => {
1107 let instance_data = builder.create_vector(key.as_bytes());
1108 let instance_offset = ContractInstanceId::create(
1109 &mut builder,
1110 &ContractInstanceIdArgs {
1111 data: Some(instance_data),
1112 },
1113 );
1114
1115 let code = key
1116 .code_hash()
1117 .map(|code| builder.create_vector(code.0.as_ref()));
1118 let key_offset = FbsContractKey::create(
1119 &mut builder,
1120 &ContractKeyArgs {
1121 instance: Some(instance_offset),
1122 code,
1123 },
1124 );
1125
1126 let update_data = match update {
1127 State(state) => {
1128 let state_data = builder.create_vector(&state.into_bytes());
1129 let state_update_offset = StateUpdate::create(
1130 &mut builder,
1131 &StateUpdateArgs {
1132 state: Some(state_data),
1133 },
1134 );
1135 FbsUpdateData::create(
1136 &mut builder,
1137 &UpdateDataArgs {
1138 update_data_type: UpdateDataType::StateUpdate,
1139 update_data: Some(state_update_offset.as_union_value()),
1140 },
1141 )
1142 }
1143 Delta(delta) => {
1144 let delta_data = builder.create_vector(&delta.into_bytes());
1145 let update_offset = DeltaUpdate::create(
1146 &mut builder,
1147 &DeltaUpdateArgs {
1148 delta: Some(delta_data),
1149 },
1150 );
1151 FbsUpdateData::create(
1152 &mut builder,
1153 &UpdateDataArgs {
1154 update_data_type: UpdateDataType::DeltaUpdate,
1155 update_data: Some(update_offset.as_union_value()),
1156 },
1157 )
1158 }
1159 StateAndDelta { state, delta } => {
1160 let state_data = builder.create_vector(&state.into_bytes());
1161 let delta_data = builder.create_vector(&delta.into_bytes());
1162
1163 let update_offset = StateAndDeltaUpdate::create(
1164 &mut builder,
1165 &StateAndDeltaUpdateArgs {
1166 state: Some(state_data),
1167 delta: Some(delta_data),
1168 },
1169 );
1170
1171 FbsUpdateData::create(
1172 &mut builder,
1173 &UpdateDataArgs {
1174 update_data_type: UpdateDataType::StateAndDeltaUpdate,
1175 update_data: Some(update_offset.as_union_value()),
1176 },
1177 )
1178 }
1179 RelatedState { related_to, state } => {
1180 let state_data = builder.create_vector(&state.into_bytes());
1181 let instance_data =
1182 builder.create_vector(related_to.encode().as_bytes());
1183
1184 let instance_offset = ContractInstanceId::create(
1185 &mut builder,
1186 &ContractInstanceIdArgs {
1187 data: Some(instance_data),
1188 },
1189 );
1190
1191 let update_offset = RelatedStateUpdate::create(
1192 &mut builder,
1193 &RelatedStateUpdateArgs {
1194 related_to: Some(instance_offset),
1195 state: Some(state_data),
1196 },
1197 );
1198
1199 FbsUpdateData::create(
1200 &mut builder,
1201 &UpdateDataArgs {
1202 update_data_type: UpdateDataType::RelatedStateUpdate,
1203 update_data: Some(update_offset.as_union_value()),
1204 },
1205 )
1206 }
1207 RelatedDelta { related_to, delta } => {
1208 let instance_data =
1209 builder.create_vector(related_to.encode().as_bytes());
1210 let delta_data = builder.create_vector(&delta.into_bytes());
1211
1212 let instance_offset = ContractInstanceId::create(
1213 &mut builder,
1214 &ContractInstanceIdArgs {
1215 data: Some(instance_data),
1216 },
1217 );
1218
1219 let update_offset = RelatedDeltaUpdate::create(
1220 &mut builder,
1221 &RelatedDeltaUpdateArgs {
1222 related_to: Some(instance_offset),
1223 delta: Some(delta_data),
1224 },
1225 );
1226
1227 FbsUpdateData::create(
1228 &mut builder,
1229 &UpdateDataArgs {
1230 update_data_type: UpdateDataType::RelatedDeltaUpdate,
1231 update_data: Some(update_offset.as_union_value()),
1232 },
1233 )
1234 }
1235 RelatedStateAndDelta {
1236 related_to,
1237 state,
1238 delta,
1239 } => {
1240 let instance_data =
1241 builder.create_vector(related_to.encode().as_bytes());
1242 let state_data = builder.create_vector(&state.into_bytes());
1243 let delta_data = builder.create_vector(&delta.into_bytes());
1244
1245 let instance_offset = ContractInstanceId::create(
1246 &mut builder,
1247 &ContractInstanceIdArgs {
1248 data: Some(instance_data),
1249 },
1250 );
1251
1252 let update_offset = RelatedStateAndDeltaUpdate::create(
1253 &mut builder,
1254 &RelatedStateAndDeltaUpdateArgs {
1255 related_to: Some(instance_offset),
1256 state: Some(state_data),
1257 delta: Some(delta_data),
1258 },
1259 );
1260
1261 FbsUpdateData::create(
1262 &mut builder,
1263 &UpdateDataArgs {
1264 update_data_type: UpdateDataType::RelatedStateAndDeltaUpdate,
1265 update_data: Some(update_offset.as_union_value()),
1266 },
1267 )
1268 }
1269 };
1270
1271 let update_notification_offset = FbsUpdateNotification::create(
1272 &mut builder,
1273 &UpdateNotificationArgs {
1274 key: Some(key_offset),
1275 update: Some(update_data),
1276 },
1277 );
1278
1279 let put_response_offset = FbsContractResponse::create(
1280 &mut builder,
1281 &ContractResponseArgs {
1282 contract_response_type: ContractResponseType::UpdateNotification,
1283 contract_response: Some(update_notification_offset.as_union_value()),
1284 },
1285 );
1286
1287 let host_response_offset = FbsHostResponse::create(
1288 &mut builder,
1289 &HostResponseArgs {
1290 response_type: HostResponseType::ContractResponse,
1291 response: Some(put_response_offset.as_union_value()),
1292 },
1293 );
1294
1295 finish_host_response_buffer(&mut builder, host_response_offset);
1296 Ok(builder.finished_data().to_vec())
1297 }
1298 ContractResponse::SubscribeResponse { .. } => todo!(),
1299 },
1300 HostResponse::DelegateResponse { key, values } => {
1301 let key_data = builder.create_vector(key.bytes());
1302 let code_hash_data = builder.create_vector(&key.code_hash().0);
1303 let key_offset = FbsDelegateKey::create(
1304 &mut builder,
1305 &DelegateKeyArgs {
1306 key: Some(key_data),
1307 code_hash: Some(code_hash_data),
1308 },
1309 );
1310 let mut messages: Vec<WIPOffset<FbsOutboundDelegateMsg>> = Vec::new();
1311 values.iter().for_each(|msg| match msg {
1312 OutboundDelegateMsg::ApplicationMessage(app) => {
1313 let instance_data = builder.create_vector(key.bytes());
1314 let instance_offset = ContractInstanceId::create(
1315 &mut builder,
1316 &ContractInstanceIdArgs {
1317 data: Some(instance_data),
1318 },
1319 );
1320 let payload_data = builder.create_vector(&app.payload);
1321 let delegate_context_data = builder.create_vector(app.context.as_ref());
1322 let app_offset = FbsApplicationMessage::create(
1323 &mut builder,
1324 &ApplicationMessageArgs {
1325 app: Some(instance_offset),
1326 payload: Some(payload_data),
1327 context: Some(delegate_context_data),
1328 processed: app.processed,
1329 },
1330 );
1331 let msg = FbsOutboundDelegateMsg::create(
1332 &mut builder,
1333 &OutboundDelegateMsgArgs {
1334 inbound_type: OutboundDelegateMsgType::common_ApplicationMessage,
1335 inbound: Some(app_offset.as_union_value()),
1336 },
1337 );
1338 messages.push(msg);
1339 }
1340 OutboundDelegateMsg::RequestUserInput(input) => {
1341 let message_data = builder.create_vector(input.message.bytes());
1342 let mut responses: Vec<WIPOffset<FbsClientResponse>> = Vec::new();
1343 input.responses.iter().for_each(|resp| {
1344 let response_data = builder.create_vector(resp.bytes());
1345 let response = FbsClientResponse::create(
1346 &mut builder,
1347 &ClientResponseArgs {
1348 data: Some(response_data),
1349 },
1350 );
1351 responses.push(response)
1352 });
1353 let responses_offset = builder.create_vector(&responses);
1354 let input_offset = FbsRequestUserInput::create(
1355 &mut builder,
1356 &RequestUserInputArgs {
1357 request_id: input.request_id,
1358 message: Some(message_data),
1359 responses: Some(responses_offset),
1360 },
1361 );
1362 let msg = FbsOutboundDelegateMsg::create(
1363 &mut builder,
1364 &OutboundDelegateMsgArgs {
1365 inbound_type: OutboundDelegateMsgType::RequestUserInput,
1366 inbound: Some(input_offset.as_union_value()),
1367 },
1368 );
1369 messages.push(msg);
1370 }
1371 OutboundDelegateMsg::ContextUpdated(context) => {
1372 let context_data = builder.create_vector(context.as_ref());
1373 let context_offset = FbsContextUpdated::create(
1374 &mut builder,
1375 &ContextUpdatedArgs {
1376 context: Some(context_data),
1377 },
1378 );
1379 let msg = FbsOutboundDelegateMsg::create(
1380 &mut builder,
1381 &OutboundDelegateMsgArgs {
1382 inbound_type: OutboundDelegateMsgType::ContextUpdated,
1383 inbound: Some(context_offset.as_union_value()),
1384 },
1385 );
1386 messages.push(msg);
1387 }
1388 OutboundDelegateMsg::GetSecretRequest(request) => {
1389 let secret_key_data = builder.create_vector(request.key.key());
1390 let secret_hash_data = builder.create_vector(request.key.hash());
1391 let secret_id_offset = FbsSecretsId::create(
1392 &mut builder,
1393 &SecretsIdArgs {
1394 key: Some(secret_key_data),
1395 hash: Some(secret_hash_data),
1396 },
1397 );
1398
1399 let delegate_context_data = builder.create_vector(request.context.as_ref());
1400 let request_offset = FbsGetSecretRequest::create(
1401 &mut builder,
1402 &GetSecretRequestArgs {
1403 key: Some(secret_id_offset),
1404 delegate_context: Some(delegate_context_data),
1405 processed: request.processed,
1406 },
1407 );
1408 let msg = FbsOutboundDelegateMsg::create(
1409 &mut builder,
1410 &OutboundDelegateMsgArgs {
1411 inbound_type: OutboundDelegateMsgType::common_GetSecretRequest,
1412 inbound: Some(request_offset.as_union_value()),
1413 },
1414 );
1415 messages.push(msg);
1416 }
1417 OutboundDelegateMsg::SetSecretRequest(request) => {
1418 let secret_key_data = builder.create_vector(request.key.key());
1419 let secret_hash_data = builder.create_vector(request.key.hash());
1420 let secret_id_offset = FbsSecretsId::create(
1421 &mut builder,
1422 &SecretsIdArgs {
1423 key: Some(secret_key_data),
1424 hash: Some(secret_hash_data),
1425 },
1426 );
1427
1428 let value_data = request
1429 .value
1430 .clone()
1431 .map(|value| builder.create_vector(value.as_slice()));
1432 let request_offset = FbsSetSecretRequest::create(
1433 &mut builder,
1434 &SetSecretRequestArgs {
1435 key: Some(secret_id_offset),
1436 value: value_data,
1437 },
1438 );
1439 let msg = FbsOutboundDelegateMsg::create(
1440 &mut builder,
1441 &OutboundDelegateMsgArgs {
1442 inbound_type: OutboundDelegateMsgType::SetSecretRequest,
1443 inbound: Some(request_offset.as_union_value()),
1444 },
1445 );
1446 messages.push(msg);
1447 }
1448 OutboundDelegateMsg::GetSecretResponse(response) => {
1449 let secret_key_data = builder.create_vector(response.key.key());
1450 let secret_hash_data = builder.create_vector(response.key.hash());
1451 let secret_id_offset = FbsSecretsId::create(
1452 &mut builder,
1453 &SecretsIdArgs {
1454 key: Some(secret_key_data),
1455 hash: Some(secret_hash_data),
1456 },
1457 );
1458
1459 let value_data = response
1460 .value
1461 .clone()
1462 .map(|value| builder.create_vector(value.as_slice()));
1463
1464 let delegate_context_data =
1465 builder.create_vector(response.context.as_ref());
1466 let response_offset = FbsGetSecretResponse::create(
1467 &mut builder,
1468 &GetSecretResponseArgs {
1469 key: Some(secret_id_offset),
1470 value: value_data,
1471 delegate_context: Some(delegate_context_data),
1472 },
1473 );
1474 let msg = FbsOutboundDelegateMsg::create(
1475 &mut builder,
1476 &OutboundDelegateMsgArgs {
1477 inbound_type: OutboundDelegateMsgType::common_GetSecretResponse,
1478 inbound: Some(response_offset.as_union_value()),
1479 },
1480 );
1481 messages.push(msg);
1482 }
1483 });
1484 let messages_offset = builder.create_vector(&messages);
1485 let delegate_response_offset = FbsDelegateResponse::create(
1486 &mut builder,
1487 &DelegateResponseArgs {
1488 key: Some(key_offset),
1489 values: Some(messages_offset),
1490 },
1491 );
1492 let host_response_offset = FbsHostResponse::create(
1493 &mut builder,
1494 &HostResponseArgs {
1495 response_type: HostResponseType::DelegateResponse,
1496 response: Some(delegate_response_offset.as_union_value()),
1497 },
1498 );
1499 finish_host_response_buffer(&mut builder, host_response_offset);
1500 Ok(builder.finished_data().to_vec())
1501 }
1502 HostResponse::Ok => {
1503 let ok_offset = FbsOk::create(&mut builder, &OkArgs { msg: None });
1504 let host_response_offset = FbsHostResponse::create(
1505 &mut builder,
1506 &HostResponseArgs {
1507 response_type: HostResponseType::Ok,
1508 response: Some(ok_offset.as_union_value()),
1509 },
1510 );
1511 finish_host_response_buffer(&mut builder, host_response_offset);
1512 Ok(builder.finished_data().to_vec())
1513 }
1514 HostResponse::QueryResponse(_) => unimplemented!(),
1515 }
1516 }
1517}
1518
1519impl Display for HostResponse {
1520 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1521 match self {
1522 HostResponse::ContractResponse(res) => match res {
1523 ContractResponse::PutResponse { key } => {
1524 f.write_fmt(format_args!("put response for `{key}`"))
1525 }
1526 ContractResponse::UpdateResponse { key, .. } => {
1527 f.write_fmt(format_args!("update response for `{key}`"))
1528 }
1529 ContractResponse::GetResponse { key, .. } => {
1530 f.write_fmt(format_args!("get response for `{key}`"))
1531 }
1532 ContractResponse::UpdateNotification { key, .. } => {
1533 f.write_fmt(format_args!("update notification for `{key}`"))
1534 }
1535 ContractResponse::SubscribeResponse { key, .. } => {
1536 f.write_fmt(format_args!("subscribe response for `{key}`"))
1537 }
1538 },
1539 HostResponse::DelegateResponse { .. } => write!(f, "delegate responses"),
1540 HostResponse::Ok => write!(f, "ok response"),
1541 HostResponse::QueryResponse(_) => write!(f, "query response"),
1542 }
1543 }
1544}
1545
1546#[derive(Clone, Serialize, Deserialize, Debug)]
1547#[non_exhaustive]
1548pub enum ContractResponse<T = WrappedState> {
1549 GetResponse {
1550 key: ContractKey,
1551 contract: Option<ContractContainer>,
1552 #[serde(bound(deserialize = "T: DeserializeOwned"))]
1553 state: T,
1554 },
1555 PutResponse {
1556 key: ContractKey,
1557 },
1558 UpdateNotification {
1560 key: ContractKey,
1561 #[serde(deserialize_with = "UpdateData::deser_update_data")]
1562 update: UpdateData<'static>,
1563 },
1564 UpdateResponse {
1566 key: ContractKey,
1567 #[serde(deserialize_with = "StateSummary::deser_state_summary")]
1568 summary: StateSummary<'static>,
1569 },
1570 SubscribeResponse {
1571 key: ContractKey,
1572 subscribed: bool,
1573 },
1574}
1575
1576impl<T> From<ContractResponse<T>> for HostResponse<T> {
1577 fn from(value: ContractResponse<T>) -> HostResponse<T> {
1578 HostResponse::ContractResponse(value)
1579 }
1580}
1581
1582#[cfg(test)]
1583mod client_request_test {
1584 use crate::client_api::{ContractRequest, TryFromFbs};
1585 use crate::contract_interface::UpdateData;
1586 use crate::generated::client_request::root_as_client_request;
1587
1588 const EXPECTED_ENCODED_CONTRACT_ID: &str = "6kVs66bKaQAC6ohr8b43SvJ95r36tc2hnG7HezmaJHF9";
1589
1590 #[test]
1591 fn test_build_contract_put_op_from_fbs() -> Result<(), Box<dyn std::error::Error>> {
1592 let put_req_op = vec![
1593 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,
1594 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,
1595 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,
1596 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,
1597 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,
1598 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,
1599 85, 111, 11, 171, 40, 85, 240, 177, 207, 81, 106, 157, 173, 90, 234, 2, 250, 253, 75,
1600 210, 62, 7, 6, 34, 75, 26, 229, 230, 107, 167, 17, 108, 8, 0, 0, 0, 1, 2, 3, 4, 5, 6,
1601 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,
1602 3, 4, 5, 6, 7, 8, 8, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8,
1603 ];
1604 let request = if let Ok(client_request) = root_as_client_request(&put_req_op) {
1605 let contract_request = client_request.client_request_as_contract_request().unwrap();
1606 ContractRequest::try_decode_fbs(&contract_request)?
1607 } else {
1608 panic!("failed to decode client request")
1609 };
1610
1611 match request {
1612 ContractRequest::Put {
1613 contract,
1614 state,
1615 related_contracts: _,
1616 subscribe,
1617 } => {
1618 assert_eq!(
1619 contract.to_string(),
1620 "WasmContainer([api=0.0.1](D8fdVLbRyMLw5mZtPRpWMFcrXGN2z8Nq8UGcLGPFBg2W))"
1621 );
1622 assert_eq!(contract.unwrap_v1().data.data(), &[1, 2, 3, 4, 5, 6, 7, 8]);
1623 assert_eq!(state.to_vec(), &[1, 2, 3, 4, 5, 6, 7, 8]);
1624 assert!(!subscribe);
1625 }
1626 _ => panic!("wrong contract request type"),
1627 }
1628
1629 Ok(())
1630 }
1631
1632 #[test]
1633 fn test_build_contract_get_op_from_fbs() -> Result<(), Box<dyn std::error::Error>> {
1634 let get_req_op = vec![
1635 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,
1636 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,
1637 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,
1638 4, 0, 0, 0, 32, 0, 0, 0, 85, 111, 11, 171, 40, 85, 240, 177, 207, 81, 106, 157, 173,
1639 90, 234, 2, 250, 253, 75, 210, 62, 7, 6, 34, 75, 26, 229, 230, 107, 167, 17, 108,
1640 ];
1641 let request = if let Ok(client_request) = root_as_client_request(&get_req_op) {
1642 let contract_request = client_request.client_request_as_contract_request().unwrap();
1643 ContractRequest::try_decode_fbs(&contract_request)?
1644 } else {
1645 panic!("failed to decode client request")
1646 };
1647
1648 match request {
1649 ContractRequest::Get {
1650 key,
1651 return_contract_code: fetch_contract,
1652 subscribe,
1653 } => {
1654 assert_eq!(key.encoded_contract_id(), EXPECTED_ENCODED_CONTRACT_ID);
1655 assert!(!fetch_contract);
1656 assert!(!subscribe);
1657 }
1658 _ => panic!("wrong contract request type"),
1659 }
1660
1661 Ok(())
1662 }
1663
1664 #[test]
1665 fn test_build_contract_update_op_from_fbs() -> Result<(), Box<dyn std::error::Error>> {
1666 let update_op = vec![
1667 4, 0, 0, 0, 220, 255, 255, 255, 8, 0, 0, 0, 0, 0, 0, 1, 232, 255, 255, 255, 8, 0, 0, 0,
1668 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,
1669 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,
1670 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,
1671 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,
1672 85, 240, 177, 207, 81, 106, 157, 173, 90, 234, 2, 250, 253, 75, 210, 62, 7, 6, 34, 75,
1673 26, 229, 230, 107, 167, 17, 108,
1674 ];
1675 let request = if let Ok(client_request) = root_as_client_request(&update_op) {
1676 let contract_request = client_request.client_request_as_contract_request().unwrap();
1677 ContractRequest::try_decode_fbs(&contract_request)?
1678 } else {
1679 panic!("failed to decode client request")
1680 };
1681
1682 match request {
1683 ContractRequest::Update { key, data } => {
1684 assert_eq!(
1685 key.encoded_contract_id(),
1686 "6kVs66bKaQAC6ohr8b43SvJ95r36tc2hnG7HezmaJHF9"
1687 );
1688 match data {
1689 UpdateData::Delta(delta) => {
1690 assert_eq!(delta.to_vec(), &[1, 2, 3, 4, 5, 6, 7, 8])
1691 }
1692 _ => panic!("wrong update data type"),
1693 }
1694 }
1695 _ => panic!("wrong contract request type"),
1696 }
1697
1698 Ok(())
1699 }
1700}