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 ProximityCache(ProximityCacheInfo),
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 seeding_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 ProximityCacheInfo,
867}
868
869#[derive(Serialize, Deserialize, Debug, Clone)]
871pub struct ProximityCacheInfo {
872 pub my_cache: Vec<ContractCacheEntry>,
874 pub neighbor_caches: Vec<NeighborCacheInfo>,
876 pub stats: ProximityStats,
878}
879
880#[derive(Serialize, Deserialize, Debug, Clone)]
881pub struct ContractCacheEntry {
882 pub contract_key: String,
884 pub cache_hash: u32,
886 pub cached_since: u64,
888}
889
890#[derive(Serialize, Deserialize, Debug, Clone)]
891pub struct NeighborCacheInfo {
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 ProximityStats {
904 pub cache_announces_sent: u64,
906 pub cache_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_cache_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 { .. } => todo!(),
1397 ContractResponse::NotFound { instance_id } => {
1398 let instance_data = builder.create_vector(instance_id.as_bytes());
1399 let instance_offset = FbsContractInstanceId::create(
1400 &mut builder,
1401 &ContractInstanceIdArgs {
1402 data: Some(instance_data),
1403 },
1404 );
1405
1406 let not_found_offset = FbsNotFound::create(
1407 &mut builder,
1408 &NotFoundArgs {
1409 instance_id: Some(instance_offset),
1410 },
1411 );
1412
1413 let contract_response_offset = FbsContractResponse::create(
1414 &mut builder,
1415 &ContractResponseArgs {
1416 contract_response_type: ContractResponseType::NotFound,
1417 contract_response: Some(not_found_offset.as_union_value()),
1418 },
1419 );
1420
1421 let response_offset = FbsHostResponse::create(
1422 &mut builder,
1423 &HostResponseArgs {
1424 response: Some(contract_response_offset.as_union_value()),
1425 response_type: HostResponseType::ContractResponse,
1426 },
1427 );
1428
1429 finish_host_response_buffer(&mut builder, response_offset);
1430 Ok(builder.finished_data().to_vec())
1431 }
1432 },
1433 HostResponse::DelegateResponse { key, values } => {
1434 let key_data = builder.create_vector(key.bytes());
1435 let code_hash_data = builder.create_vector(&key.code_hash().0);
1436 let key_offset = FbsDelegateKey::create(
1437 &mut builder,
1438 &DelegateKeyArgs {
1439 key: Some(key_data),
1440 code_hash: Some(code_hash_data),
1441 },
1442 );
1443 let mut messages: Vec<WIPOffset<FbsOutboundDelegateMsg>> = Vec::new();
1444 values.iter().for_each(|msg| match msg {
1445 OutboundDelegateMsg::ApplicationMessage(app) => {
1446 let instance_data = builder.create_vector(key.bytes());
1447 let instance_offset = FbsContractInstanceId::create(
1448 &mut builder,
1449 &ContractInstanceIdArgs {
1450 data: Some(instance_data),
1451 },
1452 );
1453 let payload_data = builder.create_vector(&app.payload);
1454 let delegate_context_data = builder.create_vector(app.context.as_ref());
1455 let app_offset = FbsApplicationMessage::create(
1456 &mut builder,
1457 &ApplicationMessageArgs {
1458 app: Some(instance_offset),
1459 payload: Some(payload_data),
1460 context: Some(delegate_context_data),
1461 processed: app.processed,
1462 },
1463 );
1464 let msg = FbsOutboundDelegateMsg::create(
1465 &mut builder,
1466 &OutboundDelegateMsgArgs {
1467 inbound_type: OutboundDelegateMsgType::common_ApplicationMessage,
1468 inbound: Some(app_offset.as_union_value()),
1469 },
1470 );
1471 messages.push(msg);
1472 }
1473 OutboundDelegateMsg::RequestUserInput(input) => {
1474 let message_data = builder.create_vector(input.message.bytes());
1475 let mut responses: Vec<WIPOffset<FbsClientResponse>> = Vec::new();
1476 input.responses.iter().for_each(|resp| {
1477 let response_data = builder.create_vector(resp.bytes());
1478 let response = FbsClientResponse::create(
1479 &mut builder,
1480 &ClientResponseArgs {
1481 data: Some(response_data),
1482 },
1483 );
1484 responses.push(response)
1485 });
1486 let responses_offset = builder.create_vector(&responses);
1487 let input_offset = FbsRequestUserInput::create(
1488 &mut builder,
1489 &RequestUserInputArgs {
1490 request_id: input.request_id,
1491 message: Some(message_data),
1492 responses: Some(responses_offset),
1493 },
1494 );
1495 let msg = FbsOutboundDelegateMsg::create(
1496 &mut builder,
1497 &OutboundDelegateMsgArgs {
1498 inbound_type: OutboundDelegateMsgType::RequestUserInput,
1499 inbound: Some(input_offset.as_union_value()),
1500 },
1501 );
1502 messages.push(msg);
1503 }
1504 OutboundDelegateMsg::ContextUpdated(context) => {
1505 let context_data = builder.create_vector(context.as_ref());
1506 let context_offset = FbsContextUpdated::create(
1507 &mut builder,
1508 &ContextUpdatedArgs {
1509 context: Some(context_data),
1510 },
1511 );
1512 let msg = FbsOutboundDelegateMsg::create(
1513 &mut builder,
1514 &OutboundDelegateMsgArgs {
1515 inbound_type: OutboundDelegateMsgType::ContextUpdated,
1516 inbound: Some(context_offset.as_union_value()),
1517 },
1518 );
1519 messages.push(msg);
1520 }
1521 OutboundDelegateMsg::GetContractRequest(_) => {
1522 tracing::error!(
1525 "GetContractRequest reached client serialization - this is a bug"
1526 );
1527 }
1528 OutboundDelegateMsg::PutContractRequest(_) => {
1529 tracing::error!(
1532 "PutContractRequest reached client serialization - this is a bug"
1533 );
1534 }
1535 OutboundDelegateMsg::UpdateContractRequest(_) => {
1536 tracing::error!(
1537 "UpdateContractRequest reached client serialization - this is a bug"
1538 );
1539 }
1540 OutboundDelegateMsg::SubscribeContractRequest(_) => {
1541 tracing::error!(
1542 "SubscribeContractRequest reached client serialization - this is a bug"
1543 );
1544 }
1545 OutboundDelegateMsg::SendDelegateMessage(_) => {
1546 tracing::error!(
1547 "SendDelegateMessage reached client serialization - this is a bug"
1548 );
1549 }
1550 });
1551 let messages_offset = builder.create_vector(&messages);
1552 let delegate_response_offset = FbsDelegateResponse::create(
1553 &mut builder,
1554 &DelegateResponseArgs {
1555 key: Some(key_offset),
1556 values: Some(messages_offset),
1557 },
1558 );
1559 let host_response_offset = FbsHostResponse::create(
1560 &mut builder,
1561 &HostResponseArgs {
1562 response_type: HostResponseType::DelegateResponse,
1563 response: Some(delegate_response_offset.as_union_value()),
1564 },
1565 );
1566 finish_host_response_buffer(&mut builder, host_response_offset);
1567 Ok(builder.finished_data().to_vec())
1568 }
1569 HostResponse::Ok => {
1570 let ok_offset = FbsOk::create(&mut builder, &OkArgs { msg: None });
1571 let host_response_offset = FbsHostResponse::create(
1572 &mut builder,
1573 &HostResponseArgs {
1574 response_type: HostResponseType::Ok,
1575 response: Some(ok_offset.as_union_value()),
1576 },
1577 );
1578 finish_host_response_buffer(&mut builder, host_response_offset);
1579 Ok(builder.finished_data().to_vec())
1580 }
1581 HostResponse::QueryResponse(_) => unimplemented!(),
1582 HostResponse::StreamChunk {
1583 stream_id,
1584 index,
1585 total,
1586 data,
1587 } => {
1588 let data_offset = builder.create_vector(&data);
1589 let chunk_offset = FbsHostStreamChunk::create(
1590 &mut builder,
1591 &FbsHostStreamChunkArgs {
1592 stream_id,
1593 index,
1594 total,
1595 data: Some(data_offset),
1596 },
1597 );
1598 let host_response_offset = FbsHostResponse::create(
1599 &mut builder,
1600 &HostResponseArgs {
1601 response_type: HostResponseType::StreamChunk,
1602 response: Some(chunk_offset.as_union_value()),
1603 },
1604 );
1605 finish_host_response_buffer(&mut builder, host_response_offset);
1606 Ok(builder.finished_data().to_vec())
1607 }
1608 HostResponse::StreamHeader { .. } => {
1609 Err(Box::new(ClientError::from(ErrorKind::Unhandled {
1613 cause: "StreamHeader is not supported over flatbuffers encoding".into(),
1614 })))
1615 }
1616 }
1617 }
1618}
1619
1620impl Display for HostResponse {
1621 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1622 match self {
1623 HostResponse::ContractResponse(res) => match res {
1624 ContractResponse::PutResponse { key } => {
1625 f.write_fmt(format_args!("put response for `{key}`"))
1626 }
1627 ContractResponse::UpdateResponse { key, .. } => {
1628 f.write_fmt(format_args!("update response for `{key}`"))
1629 }
1630 ContractResponse::GetResponse { key, .. } => {
1631 f.write_fmt(format_args!("get response for `{key}`"))
1632 }
1633 ContractResponse::UpdateNotification { key, .. } => {
1634 f.write_fmt(format_args!("update notification for `{key}`"))
1635 }
1636 ContractResponse::SubscribeResponse { key, .. } => {
1637 f.write_fmt(format_args!("subscribe response for `{key}`"))
1638 }
1639 ContractResponse::NotFound { instance_id } => {
1640 f.write_fmt(format_args!("not found for `{instance_id}`"))
1641 }
1642 },
1643 HostResponse::DelegateResponse { .. } => write!(f, "delegate responses"),
1644 HostResponse::Ok => write!(f, "ok response"),
1645 HostResponse::QueryResponse(_) => write!(f, "query response"),
1646 HostResponse::StreamChunk {
1647 stream_id,
1648 index,
1649 total,
1650 ..
1651 } => write!(f, "stream chunk {index}/{total} (stream {stream_id})"),
1652 HostResponse::StreamHeader {
1653 stream_id,
1654 total_bytes,
1655 ..
1656 } => write!(f, "stream header (stream {stream_id}, {total_bytes} bytes)"),
1657 }
1658 }
1659}
1660
1661#[derive(Clone, Serialize, Deserialize, Debug)]
1662#[non_exhaustive]
1663pub enum ContractResponse<T = WrappedState> {
1664 GetResponse {
1665 key: ContractKey,
1666 contract: Option<ContractContainer>,
1667 #[serde(bound(deserialize = "T: DeserializeOwned"))]
1668 state: T,
1669 },
1670 PutResponse {
1671 key: ContractKey,
1672 },
1673 UpdateNotification {
1675 key: ContractKey,
1676 #[serde(deserialize_with = "UpdateData::deser_update_data")]
1677 update: UpdateData<'static>,
1678 },
1679 UpdateResponse {
1681 key: ContractKey,
1682 #[serde(deserialize_with = "StateSummary::deser_state_summary")]
1683 summary: StateSummary<'static>,
1684 },
1685 SubscribeResponse {
1686 key: ContractKey,
1687 subscribed: bool,
1688 },
1689 NotFound {
1693 instance_id: ContractInstanceId,
1695 },
1696}
1697
1698impl<T> From<ContractResponse<T>> for HostResponse<T> {
1699 fn from(value: ContractResponse<T>) -> HostResponse<T> {
1700 HostResponse::ContractResponse(value)
1701 }
1702}
1703
1704#[cfg(test)]
1705mod client_request_test {
1706 use crate::client_api::{ContractRequest, TryFromFbs};
1707 use crate::contract_interface::UpdateData;
1708 use crate::generated::client_request::root_as_client_request;
1709
1710 const EXPECTED_ENCODED_CONTRACT_ID: &str = "6kVs66bKaQAC6ohr8b43SvJ95r36tc2hnG7HezmaJHF9";
1711
1712 #[test]
1713 fn test_build_contract_put_op_from_fbs() -> Result<(), Box<dyn std::error::Error>> {
1714 let put_req_op = vec![
1715 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,
1716 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,
1717 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,
1718 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,
1719 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,
1720 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,
1721 85, 111, 11, 171, 40, 85, 240, 177, 207, 81, 106, 157, 173, 90, 234, 2, 250, 253, 75,
1722 210, 62, 7, 6, 34, 75, 26, 229, 230, 107, 167, 17, 108, 8, 0, 0, 0, 1, 2, 3, 4, 5, 6,
1723 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,
1724 3, 4, 5, 6, 7, 8, 8, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8,
1725 ];
1726 let request = if let Ok(client_request) = root_as_client_request(&put_req_op) {
1727 let contract_request = client_request.client_request_as_contract_request().unwrap();
1728 ContractRequest::try_decode_fbs(&contract_request)?
1729 } else {
1730 panic!("failed to decode client request")
1731 };
1732
1733 match request {
1734 ContractRequest::Put {
1735 contract,
1736 state,
1737 related_contracts: _,
1738 subscribe,
1739 blocking_subscribe,
1740 } => {
1741 assert_eq!(
1742 contract.to_string(),
1743 "WasmContainer([api=0.0.1](D8fdVLbRyMLw5mZtPRpWMFcrXGN2z8Nq8UGcLGPFBg2W))"
1744 );
1745 assert_eq!(contract.unwrap_v1().data.data(), &[1, 2, 3, 4, 5, 6, 7, 8]);
1746 assert_eq!(state.to_vec(), &[1, 2, 3, 4, 5, 6, 7, 8]);
1747 assert!(!subscribe);
1748 assert!(!blocking_subscribe);
1749 }
1750 _ => panic!("wrong contract request type"),
1751 }
1752
1753 Ok(())
1754 }
1755
1756 #[test]
1757 fn test_build_contract_get_op_from_fbs() -> Result<(), Box<dyn std::error::Error>> {
1758 let get_req_op = vec![
1759 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,
1760 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,
1761 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,
1762 4, 0, 0, 0, 32, 0, 0, 0, 85, 111, 11, 171, 40, 85, 240, 177, 207, 81, 106, 157, 173,
1763 90, 234, 2, 250, 253, 75, 210, 62, 7, 6, 34, 75, 26, 229, 230, 107, 167, 17, 108,
1764 ];
1765 let request = if let Ok(client_request) = root_as_client_request(&get_req_op) {
1766 let contract_request = client_request.client_request_as_contract_request().unwrap();
1767 ContractRequest::try_decode_fbs(&contract_request)?
1768 } else {
1769 panic!("failed to decode client request")
1770 };
1771
1772 match request {
1773 ContractRequest::Get {
1774 key,
1775 return_contract_code: fetch_contract,
1776 subscribe,
1777 blocking_subscribe,
1778 } => {
1779 assert_eq!(key.encode(), EXPECTED_ENCODED_CONTRACT_ID);
1780 assert!(!fetch_contract);
1781 assert!(!subscribe);
1782 assert!(!blocking_subscribe);
1783 }
1784 _ => panic!("wrong contract request type"),
1785 }
1786
1787 Ok(())
1788 }
1789
1790 #[test]
1791 fn test_build_contract_update_op_from_fbs() -> Result<(), Box<dyn std::error::Error>> {
1792 let update_op = vec![
1793 4, 0, 0, 0, 220, 255, 255, 255, 8, 0, 0, 0, 0, 0, 0, 1, 232, 255, 255, 255, 8, 0, 0, 0,
1794 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,
1795 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,
1796 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,
1797 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,
1798 85, 240, 177, 207, 81, 106, 157, 173, 90, 234, 2, 250, 253, 75, 210, 62, 7, 6, 34, 75,
1799 26, 229, 230, 107, 167, 17, 108,
1800 ];
1801 let request = if let Ok(client_request) = root_as_client_request(&update_op) {
1802 let contract_request = client_request.client_request_as_contract_request().unwrap();
1803 ContractRequest::try_decode_fbs(&contract_request)?
1804 } else {
1805 panic!("failed to decode client request")
1806 };
1807
1808 match request {
1809 ContractRequest::Update { key, data } => {
1810 assert_eq!(
1811 key.encoded_contract_id(),
1812 "6kVs66bKaQAC6ohr8b43SvJ95r36tc2hnG7HezmaJHF9"
1813 );
1814 match data {
1815 UpdateData::Delta(delta) => {
1816 assert_eq!(delta.to_vec(), &[1, 2, 3, 4, 5, 6, 7, 8])
1817 }
1818 _ => panic!("wrong update data type"),
1819 }
1820 }
1821 _ => panic!("wrong contract request type"),
1822 }
1823
1824 Ok(())
1825 }
1826}