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