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