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