1use flatbuffers::WIPOffset;
2use std::borrow::Cow;
3use std::fmt::Display;
4use std::net::SocketAddr;
5
6use serde::{de::DeserializeOwned, Deserialize, Serialize};
7
8use crate::client_api::TryFromFbs;
9use crate::generated::client_request::{
10 root_as_client_request, ClientRequestType, ContractRequest as FbsContractRequest,
11 ContractRequestType, DelegateRequest as FbsDelegateRequest, DelegateRequestType,
12};
13
14use crate::delegate_interface::DelegateContext;
15use crate::generated::common::{
16 ApplicationMessage as FbsApplicationMessage, ApplicationMessageArgs, ContractCode,
17 ContractCodeArgs, ContractContainer as FbsContractContainer, ContractContainerArgs,
18 ContractInstanceId, ContractInstanceIdArgs, ContractKey as FbsContractKey, ContractKeyArgs,
19 ContractType, DeltaUpdate, DeltaUpdateArgs, GetSecretRequest as FbsGetSecretRequest,
20 GetSecretRequestArgs, GetSecretResponse as FbsGetSecretResponse, GetSecretResponseArgs,
21 RelatedDeltaUpdate, RelatedDeltaUpdateArgs, RelatedStateAndDeltaUpdate,
22 RelatedStateAndDeltaUpdateArgs, RelatedStateUpdate, RelatedStateUpdateArgs,
23 SecretsId as FbsSecretsId, SecretsIdArgs, StateAndDeltaUpdate, StateAndDeltaUpdateArgs,
24 StateUpdate, StateUpdateArgs, UpdateData as FbsUpdateData, UpdateDataArgs, UpdateDataType,
25 WasmContractV1, WasmContractV1Args,
26};
27use crate::generated::host_response::{
28 finish_host_response_buffer, ClientResponse as FbsClientResponse, ClientResponseArgs,
29 ContextUpdated as FbsContextUpdated, ContextUpdatedArgs,
30 ContractResponse as FbsContractResponse, ContractResponseArgs, ContractResponseType,
31 DelegateKey as FbsDelegateKey, DelegateKeyArgs, DelegateResponse as FbsDelegateResponse,
32 DelegateResponseArgs, GetResponse as FbsGetResponse, GetResponseArgs,
33 HostResponse as FbsHostResponse, HostResponseArgs, HostResponseType, Ok as FbsOk, OkArgs,
34 OutboundDelegateMsg as FbsOutboundDelegateMsg, OutboundDelegateMsgArgs,
35 OutboundDelegateMsgType, PutResponse as FbsPutResponse, PutResponseArgs,
36 RequestUserInput as FbsRequestUserInput, RequestUserInputArgs,
37 SetSecretRequest as FbsSetSecretRequest, SetSecretRequestArgs,
38 UpdateNotification as FbsUpdateNotification, UpdateNotificationArgs,
39 UpdateResponse as FbsUpdateResponse, UpdateResponseArgs,
40};
41use crate::prelude::ContractContainer::Wasm;
42use crate::prelude::ContractWasmAPIVersion::V1;
43use crate::prelude::UpdateData::{
44 Delta, RelatedDelta, RelatedState, RelatedStateAndDelta, State, StateAndDelta,
45};
46use crate::{
47 delegate_interface::{DelegateKey, InboundDelegateMsg, OutboundDelegateMsg},
48 prelude::{
49 ContractKey, DelegateContainer, GetSecretRequest, Parameters, RelatedContracts, SecretsId,
50 StateSummary, UpdateData, WrappedState,
51 },
52 versioning::ContractContainer,
53};
54
55use super::WsApiError;
56
57#[derive(Debug, Serialize, Deserialize)]
58pub struct ClientError {
59 kind: Box<ErrorKind>,
60}
61
62impl ClientError {
63 pub fn into_fbs_bytes(self) -> Result<Vec<u8>, Box<ClientError>> {
64 use crate::generated::host_response::{Error, ErrorArgs};
65 let mut builder = flatbuffers::FlatBufferBuilder::new();
66 let msg_offset = builder.create_string(&self.to_string());
67 let err_offset = Error::create(
68 &mut builder,
69 &ErrorArgs {
70 msg: Some(msg_offset),
71 },
72 );
73 let host_response_offset = FbsHostResponse::create(
74 &mut builder,
75 &HostResponseArgs {
76 response_type: HostResponseType::Ok,
77 response: Some(err_offset.as_union_value()),
78 },
79 );
80 finish_host_response_buffer(&mut builder, host_response_offset);
81 Ok(builder.finished_data().to_vec())
82 }
83
84 pub fn kind(&self) -> &ErrorKind {
85 &self.kind
86 }
87}
88
89impl From<ErrorKind> for ClientError {
90 fn from(kind: ErrorKind) -> Self {
91 ClientError {
92 kind: Box::new(kind),
93 }
94 }
95}
96
97impl<T: Into<Cow<'static, str>>> From<T> for ClientError {
98 fn from(cause: T) -> Self {
99 ClientError {
100 kind: Box::new(ErrorKind::Unhandled {
101 cause: cause.into(),
102 }),
103 }
104 }
105}
106
107#[derive(thiserror::Error, Debug, Serialize, Deserialize, Clone)]
108#[non_exhaustive]
109pub enum ErrorKind {
110 #[error("comm channel between client/host closed")]
111 ChannelClosed,
112 #[error("error while deserializing: {cause}")]
113 DeserializationError { cause: Cow<'static, str> },
114 #[error("client disconnected")]
115 Disconnect,
116 #[error("failed while trying to unpack state for {0}")]
117 IncorrectState(ContractKey),
118 #[error("node not available")]
119 NodeUnavailable,
120 #[error("lost the connection with the protocol handling connections")]
121 TransportProtocolDisconnect,
122 #[error("unhandled error: {cause}")]
123 Unhandled { cause: Cow<'static, str> },
124 #[error("unknown client id: {0}")]
125 UnknownClient(usize),
126 #[error(transparent)]
127 RequestError(#[from] RequestError),
128 #[error("error while executing operation in the network: {cause}")]
129 OperationError { cause: Cow<'static, str> },
130 #[error("operation timed out")]
132 FailedOperation,
133 #[error("peer should shutdown")]
134 Shutdown,
135}
136
137impl Display for ClientError {
138 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
139 write!(f, "client error: {}", self.kind)
140 }
141}
142
143impl std::error::Error for ClientError {}
144
145#[derive(Debug, thiserror::Error, Serialize, Deserialize, Clone)]
146#[non_exhaustive]
147pub enum RequestError {
148 #[error(transparent)]
149 ContractError(#[from] ContractError),
150 #[error(transparent)]
151 DelegateError(#[from] DelegateError),
152 #[error("client disconnect")]
153 Disconnect,
154 #[error("operation timed out")]
155 Timeout,
156}
157
158#[derive(Debug, thiserror::Error, Serialize, Deserialize, Clone)]
160#[non_exhaustive]
161pub enum DelegateError {
162 #[error("error while registering delegate {0}")]
163 RegisterError(DelegateKey),
164 #[error("execution error, cause {0}")]
165 ExecutionError(Cow<'static, str>),
166 #[error("missing delegate {0}")]
167 Missing(DelegateKey),
168 #[error("missing secret `{secret}` for delegate {key}")]
169 MissingSecret { key: DelegateKey, secret: SecretsId },
170 #[error("forbidden access to secret: {0}")]
171 ForbiddenSecretAccess(SecretsId),
172}
173
174#[derive(Debug, thiserror::Error, Serialize, Deserialize, Clone)]
176#[non_exhaustive]
177pub enum ContractError {
178 #[error("failed to get contract {key}, reason: {cause}")]
179 Get {
180 key: ContractKey,
181 cause: Cow<'static, str>,
182 },
183 #[error("put error for contract {key}, reason: {cause}")]
184 Put {
185 key: ContractKey,
186 cause: Cow<'static, str>,
187 },
188 #[error("update error for contract {key}, reason: {cause}")]
189 Update {
190 key: ContractKey,
191 cause: Cow<'static, str>,
192 },
193 #[error("failed to subscribe for contract {key}, reason: {cause}")]
194 Subscribe {
195 key: ContractKey,
196 cause: Cow<'static, str>,
197 },
198 #[error("dependency contract stack overflow : {key}")]
200 ContractStackOverflow {
201 key: crate::contract_interface::ContractInstanceId,
202 },
203 #[error("missing related contract: {key}")]
204 MissingRelated {
205 key: crate::contract_interface::ContractInstanceId,
206 },
207 #[error("missing contract: {key}")]
208 MissingContract {
209 key: crate::contract_interface::ContractInstanceId,
210 },
211}
212
213impl ContractError {
214 const EXECUTION_ERROR: &'static str = "execution error";
215 const INVALID_PUT: &'static str = "invalid put";
216
217 pub fn update_exec_error(key: ContractKey, additional_info: impl std::fmt::Display) -> Self {
218 Self::Update {
219 key,
220 cause: format!(
221 "{exec_err}: {additional_info}",
222 exec_err = Self::EXECUTION_ERROR
223 )
224 .into(),
225 }
226 }
227
228 pub fn invalid_put(key: ContractKey) -> Self {
229 Self::Put {
230 key,
231 cause: Self::INVALID_PUT.into(),
232 }
233 }
234
235 pub fn invalid_update(key: ContractKey) -> Self {
236 Self::Update {
237 key,
238 cause: Self::INVALID_PUT.into(),
239 }
240 }
241}
242
243#[derive(Serialize, Deserialize, Debug, Clone)]
245#[non_exhaustive]
246pub enum ClientRequest<'a> {
248 DelegateOp(#[serde(borrow)] DelegateRequest<'a>),
249 ContractOp(#[serde(borrow)] ContractRequest<'a>),
250 Disconnect {
251 cause: Option<Cow<'static, str>>,
252 },
253 Authenticate {
254 token: String,
255 },
256 NodeQueries(NodeQuery),
257 Close,
259}
260
261#[derive(Serialize, Deserialize, Debug, Clone)]
262pub enum NodeQuery {
263 ConnectedPeers,
264 SubscriptionInfo,
265}
266
267#[derive(Serialize, Deserialize, Debug, Clone)]
269pub struct ConnectedPeers {}
270
271impl ClientRequest<'_> {
272 pub fn into_owned(self) -> ClientRequest<'static> {
273 match self {
274 ClientRequest::ContractOp(op) => {
275 let owned = match op {
276 ContractRequest::Put {
277 contract,
278 state,
279 related_contracts,
280 subscribe,
281 } => {
282 let related_contracts = related_contracts.into_owned();
283 ContractRequest::Put {
284 contract,
285 state,
286 related_contracts,
287 subscribe,
288 }
289 }
290 ContractRequest::Update { key, data } => {
291 let data = data.into_owned();
292 ContractRequest::Update { key, data }
293 }
294 ContractRequest::Get {
295 key,
296 return_contract_code,
297 subscribe,
298 } => ContractRequest::Get {
299 key,
300 return_contract_code,
301 subscribe,
302 },
303 ContractRequest::Subscribe { key, summary } => ContractRequest::Subscribe {
304 key,
305 summary: summary.map(StateSummary::into_owned),
306 },
307 };
308 owned.into()
309 }
310 ClientRequest::DelegateOp(op) => {
311 let op = op.into_owned();
312 ClientRequest::DelegateOp(op)
313 }
314 ClientRequest::Disconnect { cause } => ClientRequest::Disconnect { cause },
315 ClientRequest::Authenticate { token } => ClientRequest::Authenticate { token },
316 ClientRequest::NodeQueries(query) => ClientRequest::NodeQueries(query),
317 ClientRequest::Close => ClientRequest::Close,
318 }
319 }
320
321 pub fn is_disconnect(&self) -> bool {
322 matches!(self, Self::Disconnect { .. })
323 }
324
325 pub fn try_decode_fbs(msg: &[u8]) -> Result<ClientRequest, WsApiError> {
326 let req = {
327 match root_as_client_request(msg) {
328 Ok(client_request) => match client_request.client_request_type() {
329 ClientRequestType::ContractRequest => {
330 let contract_request =
331 client_request.client_request_as_contract_request().unwrap();
332 ContractRequest::try_decode_fbs(&contract_request)?.into()
333 }
334 ClientRequestType::DelegateRequest => {
335 let delegate_request =
336 client_request.client_request_as_delegate_request().unwrap();
337 DelegateRequest::try_decode_fbs(&delegate_request)?.into()
338 }
339 ClientRequestType::Disconnect => {
340 let delegate_request =
341 client_request.client_request_as_disconnect().unwrap();
342 let cause = delegate_request
343 .cause()
344 .map(|cause_msg| cause_msg.to_string().into());
345 ClientRequest::Disconnect { cause }
346 }
347 ClientRequestType::Authenticate => {
348 let auth_req = client_request.client_request_as_authenticate().unwrap();
349 let token = auth_req.token();
350 ClientRequest::Authenticate {
351 token: token.to_owned(),
352 }
353 }
354 _ => unreachable!(),
355 },
356 Err(e) => {
357 let cause = format!("{e}");
358 return Err(WsApiError::deserialization(cause));
359 }
360 }
361 };
362
363 Ok(req)
364 }
365}
366
367#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
368#[non_exhaustive]
369pub enum ContractRequest<'a> {
370 Put {
372 contract: ContractContainer,
373 state: WrappedState,
375 #[serde(borrow)]
377 related_contracts: RelatedContracts<'a>,
378 subscribe: bool,
380 },
381 Update {
383 key: ContractKey,
384 #[serde(borrow)]
385 data: UpdateData<'a>,
386 },
387 Get {
389 key: ContractKey,
391 return_contract_code: bool,
393 subscribe: bool,
395 },
396 Subscribe {
399 key: ContractKey,
400 summary: Option<StateSummary<'a>>,
401 },
402}
403
404impl ContractRequest<'_> {
405 pub fn into_owned(self) -> ContractRequest<'static> {
406 match self {
407 Self::Put {
408 contract,
409 state,
410 related_contracts,
411 subscribe,
412 } => ContractRequest::Put {
413 contract,
414 state,
415 related_contracts: related_contracts.into_owned(),
416 subscribe,
417 },
418 Self::Update { key, data } => ContractRequest::Update {
419 key,
420 data: data.into_owned(),
421 },
422 Self::Get {
423 key,
424 return_contract_code: fetch_contract,
425 subscribe,
426 } => ContractRequest::Get {
427 key,
428 return_contract_code: fetch_contract,
429 subscribe,
430 },
431 Self::Subscribe { key, summary } => ContractRequest::Subscribe {
432 key,
433 summary: summary.map(StateSummary::into_owned),
434 },
435 }
436 }
437}
438
439impl<'a> From<ContractRequest<'a>> for ClientRequest<'a> {
440 fn from(op: ContractRequest<'a>) -> Self {
441 ClientRequest::ContractOp(op)
442 }
443}
444
445impl<'a> TryFromFbs<&FbsContractRequest<'a>> for ContractRequest<'a> {
447 fn try_decode_fbs(request: &FbsContractRequest<'a>) -> Result<Self, WsApiError> {
448 let req = {
449 match request.contract_request_type() {
450 ContractRequestType::Get => {
451 let get = request.contract_request_as_get().unwrap();
452 let key = ContractKey::try_decode_fbs(&get.key())?;
453 let fetch_contract = get.fetch_contract();
454 let subscribe = get.subscribe();
455 ContractRequest::Get {
456 key,
457 return_contract_code: fetch_contract,
458 subscribe,
459 }
460 }
461 ContractRequestType::Put => {
462 let put = request.contract_request_as_put().unwrap();
463 let contract = ContractContainer::try_decode_fbs(&put.container())?;
464 let state = WrappedState::new(put.wrapped_state().bytes().to_vec());
465 let related_contracts =
466 RelatedContracts::try_decode_fbs(&put.related_contracts())?.into_owned();
467 let subscribe = put.subscribe();
468 ContractRequest::Put {
469 contract,
470 state,
471 related_contracts,
472 subscribe,
473 }
474 }
475 ContractRequestType::Update => {
476 let update = request.contract_request_as_update().unwrap();
477 let key = ContractKey::try_decode_fbs(&update.key())?;
478 let data = UpdateData::try_decode_fbs(&update.data())?.into_owned();
479 ContractRequest::Update { key, data }
480 }
481 ContractRequestType::Subscribe => {
482 let subscribe = request.contract_request_as_subscribe().unwrap();
483 let key = ContractKey::try_decode_fbs(&subscribe.key())?;
484 let summary = subscribe
485 .summary()
486 .map(|summary_data| StateSummary::from(summary_data.bytes()));
487 ContractRequest::Subscribe { key, summary }
488 }
489 _ => unreachable!(),
490 }
491 };
492
493 Ok(req)
494 }
495}
496
497impl<'a> From<DelegateRequest<'a>> for ClientRequest<'a> {
498 fn from(op: DelegateRequest<'a>) -> Self {
499 ClientRequest::DelegateOp(op)
500 }
501}
502
503#[derive(Serialize, Deserialize, Debug, Clone)]
504#[non_exhaustive]
505pub enum DelegateRequest<'a> {
506 ApplicationMessages {
507 key: DelegateKey,
508 #[serde(deserialize_with = "Parameters::deser_params")]
509 params: Parameters<'a>,
510 #[serde(borrow)]
511 inbound: Vec<InboundDelegateMsg<'a>>,
512 },
513 GetSecretRequest {
514 key: DelegateKey,
515 #[serde(borrow)]
516 params: Parameters<'a>,
517 get_request: GetSecretRequest,
518 },
519 RegisterDelegate {
520 delegate: DelegateContainer,
521 cipher: [u8; 32],
522 nonce: [u8; 24],
523 },
524 UnregisterDelegate(DelegateKey),
525}
526
527impl DelegateRequest<'_> {
528 pub const DEFAULT_CIPHER: [u8; 32] = [
529 0, 24, 22, 150, 112, 207, 24, 65, 182, 161, 169, 227, 66, 182, 237, 215, 206, 164, 58, 161,
530 64, 108, 157, 195, 0, 0, 0, 0, 0, 0, 0, 0,
531 ];
532
533 pub const DEFAULT_NONCE: [u8; 24] = [
534 57, 18, 79, 116, 63, 134, 93, 39, 208, 161, 156, 229, 222, 247, 111, 79, 210, 126, 127, 55,
535 224, 150, 139, 80,
536 ];
537
538 pub fn into_owned(self) -> DelegateRequest<'static> {
539 match self {
540 DelegateRequest::ApplicationMessages {
541 key,
542 inbound,
543 params,
544 } => DelegateRequest::ApplicationMessages {
545 key,
546 params: params.into_owned(),
547 inbound: inbound.into_iter().map(|e| e.into_owned()).collect(),
548 },
549 DelegateRequest::GetSecretRequest {
550 key,
551 get_request,
552 params,
553 } => DelegateRequest::GetSecretRequest {
554 key,
555 get_request,
556 params: params.into_owned(),
557 },
558 DelegateRequest::RegisterDelegate {
559 delegate,
560 cipher,
561 nonce,
562 } => DelegateRequest::RegisterDelegate {
563 delegate,
564 cipher,
565 nonce,
566 },
567 DelegateRequest::UnregisterDelegate(key) => DelegateRequest::UnregisterDelegate(key),
568 }
569 }
570
571 pub fn key(&self) -> &DelegateKey {
572 match self {
573 DelegateRequest::ApplicationMessages { key, .. } => key,
574 DelegateRequest::GetSecretRequest { key, .. } => key,
575 DelegateRequest::RegisterDelegate { delegate, .. } => delegate.key(),
576 DelegateRequest::UnregisterDelegate(key) => key,
577 }
578 }
579}
580
581impl Display for ClientRequest<'_> {
582 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
583 match self {
584 ClientRequest::ContractOp(op) => match op {
585 ContractRequest::Put {
586 contract, state, ..
587 } => {
588 write!(
589 f,
590 "ContractRequest::Put for contract `{contract}` with state {state}"
591 )
592 }
593 ContractRequest::Update { key, .. } => write!(f, "update request for {key}"),
594 ContractRequest::Get {
595 key,
596 return_contract_code: contract,
597 ..
598 } => {
599 write!(
600 f,
601 "ContractRequest::Get for key `{key}` (fetch full contract: {contract})"
602 )
603 }
604 ContractRequest::Subscribe { key, .. } => {
605 write!(f, "ContractRequest::Subscribe for `{key}`")
606 }
607 },
608 ClientRequest::DelegateOp(op) => {
609 match op {
610 DelegateRequest::ApplicationMessages { key, inbound, .. } => {
611 write!(
612 f,
613 "DelegateRequest::ApplicationMessages for `{key}` with {} messages",
614 inbound.len()
615 )
616 }
617 DelegateRequest::GetSecretRequest {
618 get_request: GetSecretRequest { key: secret_id, .. },
619 key,
620 ..
621 } => {
622 write!(f, "DelegateRequest::GetSecretRequest secret_id `{secret_id}` for key `{key}`")
623 }
624 DelegateRequest::RegisterDelegate { delegate, .. } => {
625 write!(
626 f,
627 "DelegateRequest::RegisterDelegate for delegate.key()=`{}`",
628 delegate.key()
629 )
630 }
631 DelegateRequest::UnregisterDelegate(key) => {
632 write!(f, "DelegateRequest::UnregisterDelegate for key `{key}`")
633 }
634 }
635 }
636 ClientRequest::Disconnect { .. } => write!(f, "client disconnected"),
637 ClientRequest::Authenticate { .. } => write!(f, "authenticate"),
638 ClientRequest::NodeQueries(query) => write!(f, "node queries: {:?}", query),
639 ClientRequest::Close => write!(f, "close"),
640 }
641 }
642}
643
644impl<'a> TryFromFbs<&FbsDelegateRequest<'a>> for DelegateRequest<'a> {
646 fn try_decode_fbs(request: &FbsDelegateRequest<'a>) -> Result<Self, WsApiError> {
647 let req = {
648 match request.delegate_request_type() {
649 DelegateRequestType::ApplicationMessages => {
650 let app_msg = request.delegate_request_as_application_messages().unwrap();
651 let key = DelegateKey::try_decode_fbs(&app_msg.key())?;
652 let params = Parameters::from(app_msg.params().bytes());
653 let inbound = app_msg
654 .inbound()
655 .iter()
656 .map(|msg| InboundDelegateMsg::try_decode_fbs(&msg))
657 .collect::<Result<Vec<_>, _>>()?;
658 DelegateRequest::ApplicationMessages {
659 key,
660 params,
661 inbound,
662 }
663 }
664 DelegateRequestType::GetSecretRequestType => {
665 let get_secret = request
666 .delegate_request_as_get_secret_request_type()
667 .unwrap();
668 let key = DelegateKey::try_decode_fbs(&get_secret.key())?;
669 let params = Parameters::from(get_secret.params().bytes().to_vec());
670 let get_request = GetSecretRequest {
671 key: SecretsId::try_decode_fbs(&get_secret.get_request().key())?,
672 context: DelegateContext::new(
673 get_secret.get_request().delegate_context().bytes().to_vec(),
674 ),
675 processed: get_secret.get_request().processed(),
676 };
677 DelegateRequest::GetSecretRequest {
678 key,
679 params,
680 get_request,
681 }
682 }
683 DelegateRequestType::RegisterDelegate => {
684 let register = request.delegate_request_as_register_delegate().unwrap();
685 let delegate = DelegateContainer::try_decode_fbs(®ister.delegate())?;
686 let cipher =
687 <[u8; 32]>::try_from(register.cipher().bytes().to_vec().as_slice())
688 .unwrap();
689 let nonce =
690 <[u8; 24]>::try_from(register.nonce().bytes().to_vec().as_slice()).unwrap();
691 DelegateRequest::RegisterDelegate {
692 delegate,
693 cipher,
694 nonce,
695 }
696 }
697 DelegateRequestType::UnregisterDelegate => {
698 let unregister = request.delegate_request_as_unregister_delegate().unwrap();
699 let key = DelegateKey::try_decode_fbs(&unregister.key())?;
700 DelegateRequest::UnregisterDelegate(key)
701 }
702 _ => unreachable!(),
703 }
704 };
705
706 Ok(req)
707 }
708}
709
710#[derive(Serialize, Deserialize, Debug)]
712#[non_exhaustive]
713pub enum HostResponse<T = WrappedState> {
714 ContractResponse(#[serde(bound(deserialize = "T: DeserializeOwned"))] ContractResponse<T>),
715 DelegateResponse {
716 key: DelegateKey,
717 values: Vec<OutboundDelegateMsg>,
718 },
719 QueryResponse(QueryResponse),
720 Ok,
722}
723
724type Peer = String;
725
726#[derive(Serialize, Deserialize, Debug)]
727pub struct SubscriptionInfo {
728 pub contract_key: ContractKey,
729 pub client_id: usize,
730 pub last_update: Option<std::time::SystemTime>,
731}
732
733#[derive(Serialize, Deserialize, Debug)]
734pub struct NetworkDebugInfo {
735 pub subscriptions: Vec<SubscriptionInfo>,
736 pub connected_peers: Vec<(Peer, SocketAddr)>,
737}
738
739#[derive(Serialize, Deserialize, Debug)]
740pub enum QueryResponse {
741 ConnectedPeers { peers: Vec<(Peer, SocketAddr)> },
742 NetworkDebug(NetworkDebugInfo),
743}
744
745impl HostResponse {
746 pub fn unwrap_put(self) -> ContractKey {
747 if let Self::ContractResponse(ContractResponse::PutResponse { key }) = self {
748 key
749 } else {
750 panic!("called `HostResponse::unwrap_put()` on other than `PutResponse` value")
751 }
752 }
753
754 pub fn unwrap_get(self) -> (WrappedState, Option<ContractContainer>) {
755 if let Self::ContractResponse(ContractResponse::GetResponse {
756 contract, state, ..
757 }) = self
758 {
759 (state, contract)
760 } else {
761 panic!("called `HostResponse::unwrap_put()` on other than `PutResponse` value")
762 }
763 }
764
765 pub fn into_fbs_bytes(self) -> Result<Vec<u8>, Box<ClientError>> {
766 let mut builder = flatbuffers::FlatBufferBuilder::new();
767 match self {
768 HostResponse::ContractResponse(res) => match res {
769 ContractResponse::PutResponse { key } => {
770 let instance_data = builder.create_vector(key.as_bytes());
771 let instance_offset = ContractInstanceId::create(
772 &mut builder,
773 &ContractInstanceIdArgs {
774 data: Some(instance_data),
775 },
776 );
777
778 let code = key
779 .code_hash()
780 .map(|code| builder.create_vector(code.0.as_ref()));
781 let key_offset = FbsContractKey::create(
782 &mut builder,
783 &ContractKeyArgs {
784 instance: Some(instance_offset),
785 code,
786 },
787 );
788
789 let put_offset = FbsPutResponse::create(
790 &mut builder,
791 &PutResponseArgs {
792 key: Some(key_offset),
793 },
794 );
795
796 let contract_response_offset = FbsContractResponse::create(
797 &mut builder,
798 &ContractResponseArgs {
799 contract_response: Some(put_offset.as_union_value()),
800 contract_response_type: ContractResponseType::PutResponse,
801 },
802 );
803
804 let response_offset = FbsHostResponse::create(
805 &mut builder,
806 &HostResponseArgs {
807 response: Some(contract_response_offset.as_union_value()),
808 response_type: HostResponseType::ContractResponse,
809 },
810 );
811
812 finish_host_response_buffer(&mut builder, response_offset);
813 Ok(builder.finished_data().to_vec())
814 }
815 ContractResponse::UpdateResponse { key, summary } => {
816 let instance_data = builder.create_vector(key.as_bytes());
817 let instance_offset = ContractInstanceId::create(
818 &mut builder,
819 &ContractInstanceIdArgs {
820 data: Some(instance_data),
821 },
822 );
823
824 let code = key
825 .code_hash()
826 .map(|code| builder.create_vector(code.0.as_ref()));
827
828 let key_offset = FbsContractKey::create(
829 &mut builder,
830 &ContractKeyArgs {
831 instance: Some(instance_offset),
832 code,
833 },
834 );
835
836 let summary_data = builder.create_vector(&summary.into_bytes());
837
838 let update_response_offset = FbsUpdateResponse::create(
839 &mut builder,
840 &UpdateResponseArgs {
841 key: Some(key_offset),
842 summary: Some(summary_data),
843 },
844 );
845
846 let contract_response_offset = FbsContractResponse::create(
847 &mut builder,
848 &ContractResponseArgs {
849 contract_response: Some(update_response_offset.as_union_value()),
850 contract_response_type: ContractResponseType::UpdateResponse,
851 },
852 );
853
854 let response_offset = FbsHostResponse::create(
855 &mut builder,
856 &HostResponseArgs {
857 response: Some(contract_response_offset.as_union_value()),
858 response_type: HostResponseType::ContractResponse,
859 },
860 );
861
862 finish_host_response_buffer(&mut builder, response_offset);
863 Ok(builder.finished_data().to_vec())
864 }
865 ContractResponse::GetResponse {
866 key,
867 contract: contract_container,
868 state,
869 } => {
870 let instance_data = builder.create_vector(key.as_bytes());
871 let instance_offset = ContractInstanceId::create(
872 &mut builder,
873 &ContractInstanceIdArgs {
874 data: Some(instance_data),
875 },
876 );
877
878 let code = key.code_hash().map(|code| builder.create_vector(&code.0));
879 let key_offset = FbsContractKey::create(
880 &mut builder,
881 &ContractKeyArgs {
882 instance: Some(instance_offset),
883 code,
884 },
885 );
886
887 let container_offset = if let Some(contract) = contract_container {
888 let data = builder.create_vector(contract.key().as_bytes());
889
890 let instance_offset = ContractInstanceId::create(
891 &mut builder,
892 &ContractInstanceIdArgs { data: Some(data) },
893 );
894
895 let code = contract
896 .key()
897 .code_hash()
898 .map(|code| builder.create_vector(&code.0));
899 let contract_key_offset = FbsContractKey::create(
900 &mut builder,
901 &ContractKeyArgs {
902 instance: Some(instance_offset),
903 code,
904 },
905 );
906
907 let contract_data =
908 builder.create_vector(contract.clone().unwrap_v1().data.data());
909 let contract_code_hash =
910 builder.create_vector(&contract.clone().unwrap_v1().data.hash().0);
911
912 let contract_code_offset = ContractCode::create(
913 &mut builder,
914 &ContractCodeArgs {
915 data: Some(contract_data),
916 code_hash: Some(contract_code_hash),
917 },
918 );
919
920 let contract_params =
921 builder.create_vector(&contract.clone().params().into_bytes());
922
923 let contract_offset = match contract {
924 Wasm(V1(..)) => WasmContractV1::create(
925 &mut builder,
926 &WasmContractV1Args {
927 key: Some(contract_key_offset),
928 data: Some(contract_code_offset),
929 parameters: Some(contract_params),
930 },
931 ),
932 };
933
934 Some(FbsContractContainer::create(
935 &mut builder,
936 &ContractContainerArgs {
937 contract_type: ContractType::WasmContractV1,
938 contract: Some(contract_offset.as_union_value()),
939 },
940 ))
941 } else {
942 None
943 };
944
945 let state_data = builder.create_vector(&state);
946
947 let get_offset = FbsGetResponse::create(
948 &mut builder,
949 &GetResponseArgs {
950 key: Some(key_offset),
951 contract: container_offset,
952 state: Some(state_data),
953 },
954 );
955
956 let contract_response_offset = FbsContractResponse::create(
957 &mut builder,
958 &ContractResponseArgs {
959 contract_response_type: ContractResponseType::GetResponse,
960 contract_response: Some(get_offset.as_union_value()),
961 },
962 );
963
964 let response_offset = FbsHostResponse::create(
965 &mut builder,
966 &HostResponseArgs {
967 response: Some(contract_response_offset.as_union_value()),
968 response_type: HostResponseType::ContractResponse,
969 },
970 );
971
972 finish_host_response_buffer(&mut builder, response_offset);
973 Ok(builder.finished_data().to_vec())
974 }
975 ContractResponse::UpdateNotification { key, update } => {
976 let instance_data = builder.create_vector(key.as_bytes());
977 let instance_offset = ContractInstanceId::create(
978 &mut builder,
979 &ContractInstanceIdArgs {
980 data: Some(instance_data),
981 },
982 );
983
984 let code = key
985 .code_hash()
986 .map(|code| builder.create_vector(code.0.as_ref()));
987 let key_offset = FbsContractKey::create(
988 &mut builder,
989 &ContractKeyArgs {
990 instance: Some(instance_offset),
991 code,
992 },
993 );
994
995 let update_data = match update {
996 State(state) => {
997 let state_data = builder.create_vector(&state.into_bytes());
998 let state_update_offset = StateUpdate::create(
999 &mut builder,
1000 &StateUpdateArgs {
1001 state: Some(state_data),
1002 },
1003 );
1004 FbsUpdateData::create(
1005 &mut builder,
1006 &UpdateDataArgs {
1007 update_data_type: UpdateDataType::StateUpdate,
1008 update_data: Some(state_update_offset.as_union_value()),
1009 },
1010 )
1011 }
1012 Delta(delta) => {
1013 let delta_data = builder.create_vector(&delta.into_bytes());
1014 let update_offset = DeltaUpdate::create(
1015 &mut builder,
1016 &DeltaUpdateArgs {
1017 delta: Some(delta_data),
1018 },
1019 );
1020 FbsUpdateData::create(
1021 &mut builder,
1022 &UpdateDataArgs {
1023 update_data_type: UpdateDataType::DeltaUpdate,
1024 update_data: Some(update_offset.as_union_value()),
1025 },
1026 )
1027 }
1028 StateAndDelta { state, delta } => {
1029 let state_data = builder.create_vector(&state.into_bytes());
1030 let delta_data = builder.create_vector(&delta.into_bytes());
1031
1032 let update_offset = StateAndDeltaUpdate::create(
1033 &mut builder,
1034 &StateAndDeltaUpdateArgs {
1035 state: Some(state_data),
1036 delta: Some(delta_data),
1037 },
1038 );
1039
1040 FbsUpdateData::create(
1041 &mut builder,
1042 &UpdateDataArgs {
1043 update_data_type: UpdateDataType::StateAndDeltaUpdate,
1044 update_data: Some(update_offset.as_union_value()),
1045 },
1046 )
1047 }
1048 RelatedState { related_to, state } => {
1049 let state_data = builder.create_vector(&state.into_bytes());
1050 let instance_data =
1051 builder.create_vector(related_to.encode().as_bytes());
1052
1053 let instance_offset = ContractInstanceId::create(
1054 &mut builder,
1055 &ContractInstanceIdArgs {
1056 data: Some(instance_data),
1057 },
1058 );
1059
1060 let update_offset = RelatedStateUpdate::create(
1061 &mut builder,
1062 &RelatedStateUpdateArgs {
1063 related_to: Some(instance_offset),
1064 state: Some(state_data),
1065 },
1066 );
1067
1068 FbsUpdateData::create(
1069 &mut builder,
1070 &UpdateDataArgs {
1071 update_data_type: UpdateDataType::RelatedStateUpdate,
1072 update_data: Some(update_offset.as_union_value()),
1073 },
1074 )
1075 }
1076 RelatedDelta { related_to, delta } => {
1077 let instance_data =
1078 builder.create_vector(related_to.encode().as_bytes());
1079 let delta_data = builder.create_vector(&delta.into_bytes());
1080
1081 let instance_offset = ContractInstanceId::create(
1082 &mut builder,
1083 &ContractInstanceIdArgs {
1084 data: Some(instance_data),
1085 },
1086 );
1087
1088 let update_offset = RelatedDeltaUpdate::create(
1089 &mut builder,
1090 &RelatedDeltaUpdateArgs {
1091 related_to: Some(instance_offset),
1092 delta: Some(delta_data),
1093 },
1094 );
1095
1096 FbsUpdateData::create(
1097 &mut builder,
1098 &UpdateDataArgs {
1099 update_data_type: UpdateDataType::RelatedDeltaUpdate,
1100 update_data: Some(update_offset.as_union_value()),
1101 },
1102 )
1103 }
1104 RelatedStateAndDelta {
1105 related_to,
1106 state,
1107 delta,
1108 } => {
1109 let instance_data =
1110 builder.create_vector(related_to.encode().as_bytes());
1111 let state_data = builder.create_vector(&state.into_bytes());
1112 let delta_data = builder.create_vector(&delta.into_bytes());
1113
1114 let instance_offset = ContractInstanceId::create(
1115 &mut builder,
1116 &ContractInstanceIdArgs {
1117 data: Some(instance_data),
1118 },
1119 );
1120
1121 let update_offset = RelatedStateAndDeltaUpdate::create(
1122 &mut builder,
1123 &RelatedStateAndDeltaUpdateArgs {
1124 related_to: Some(instance_offset),
1125 state: Some(state_data),
1126 delta: Some(delta_data),
1127 },
1128 );
1129
1130 FbsUpdateData::create(
1131 &mut builder,
1132 &UpdateDataArgs {
1133 update_data_type: UpdateDataType::RelatedStateAndDeltaUpdate,
1134 update_data: Some(update_offset.as_union_value()),
1135 },
1136 )
1137 }
1138 };
1139
1140 let update_notification_offset = FbsUpdateNotification::create(
1141 &mut builder,
1142 &UpdateNotificationArgs {
1143 key: Some(key_offset),
1144 update: Some(update_data),
1145 },
1146 );
1147
1148 let put_response_offset = FbsContractResponse::create(
1149 &mut builder,
1150 &ContractResponseArgs {
1151 contract_response_type: ContractResponseType::UpdateNotification,
1152 contract_response: Some(update_notification_offset.as_union_value()),
1153 },
1154 );
1155
1156 let host_response_offset = FbsHostResponse::create(
1157 &mut builder,
1158 &HostResponseArgs {
1159 response_type: HostResponseType::ContractResponse,
1160 response: Some(put_response_offset.as_union_value()),
1161 },
1162 );
1163
1164 finish_host_response_buffer(&mut builder, host_response_offset);
1165 Ok(builder.finished_data().to_vec())
1166 }
1167 ContractResponse::SubscribeResponse { .. } => todo!(),
1168 },
1169 HostResponse::DelegateResponse { key, values } => {
1170 let key_data = builder.create_vector(key.bytes());
1171 let code_hash_data = builder.create_vector(&key.code_hash().0);
1172 let key_offset = FbsDelegateKey::create(
1173 &mut builder,
1174 &DelegateKeyArgs {
1175 key: Some(key_data),
1176 code_hash: Some(code_hash_data),
1177 },
1178 );
1179 let mut messages: Vec<WIPOffset<FbsOutboundDelegateMsg>> = Vec::new();
1180 values.iter().for_each(|msg| match msg {
1181 OutboundDelegateMsg::ApplicationMessage(app) => {
1182 let instance_data = builder.create_vector(key.bytes());
1183 let instance_offset = ContractInstanceId::create(
1184 &mut builder,
1185 &ContractInstanceIdArgs {
1186 data: Some(instance_data),
1187 },
1188 );
1189 let payload_data = builder.create_vector(&app.payload);
1190 let delegate_context_data = builder.create_vector(app.context.as_ref());
1191 let app_offset = FbsApplicationMessage::create(
1192 &mut builder,
1193 &ApplicationMessageArgs {
1194 app: Some(instance_offset),
1195 payload: Some(payload_data),
1196 context: Some(delegate_context_data),
1197 processed: app.processed,
1198 },
1199 );
1200 let msg = FbsOutboundDelegateMsg::create(
1201 &mut builder,
1202 &OutboundDelegateMsgArgs {
1203 inbound_type: OutboundDelegateMsgType::common_ApplicationMessage,
1204 inbound: Some(app_offset.as_union_value()),
1205 },
1206 );
1207 messages.push(msg);
1208 }
1209 OutboundDelegateMsg::RequestUserInput(input) => {
1210 let message_data = builder.create_vector(input.message.bytes());
1211 let mut responses: Vec<WIPOffset<FbsClientResponse>> = Vec::new();
1212 input.responses.iter().for_each(|resp| {
1213 let response_data = builder.create_vector(resp.bytes());
1214 let response = FbsClientResponse::create(
1215 &mut builder,
1216 &ClientResponseArgs {
1217 data: Some(response_data),
1218 },
1219 );
1220 responses.push(response)
1221 });
1222 let responses_offset = builder.create_vector(&responses);
1223 let input_offset = FbsRequestUserInput::create(
1224 &mut builder,
1225 &RequestUserInputArgs {
1226 request_id: input.request_id,
1227 message: Some(message_data),
1228 responses: Some(responses_offset),
1229 },
1230 );
1231 let msg = FbsOutboundDelegateMsg::create(
1232 &mut builder,
1233 &OutboundDelegateMsgArgs {
1234 inbound_type: OutboundDelegateMsgType::RequestUserInput,
1235 inbound: Some(input_offset.as_union_value()),
1236 },
1237 );
1238 messages.push(msg);
1239 }
1240 OutboundDelegateMsg::ContextUpdated(context) => {
1241 let context_data = builder.create_vector(context.as_ref());
1242 let context_offset = FbsContextUpdated::create(
1243 &mut builder,
1244 &ContextUpdatedArgs {
1245 context: Some(context_data),
1246 },
1247 );
1248 let msg = FbsOutboundDelegateMsg::create(
1249 &mut builder,
1250 &OutboundDelegateMsgArgs {
1251 inbound_type: OutboundDelegateMsgType::ContextUpdated,
1252 inbound: Some(context_offset.as_union_value()),
1253 },
1254 );
1255 messages.push(msg);
1256 }
1257 OutboundDelegateMsg::GetSecretRequest(request) => {
1258 let secret_key_data = builder.create_vector(request.key.key());
1259 let secret_hash_data = builder.create_vector(request.key.hash());
1260 let secret_id_offset = FbsSecretsId::create(
1261 &mut builder,
1262 &SecretsIdArgs {
1263 key: Some(secret_key_data),
1264 hash: Some(secret_hash_data),
1265 },
1266 );
1267
1268 let delegate_context_data = builder.create_vector(request.context.as_ref());
1269 let request_offset = FbsGetSecretRequest::create(
1270 &mut builder,
1271 &GetSecretRequestArgs {
1272 key: Some(secret_id_offset),
1273 delegate_context: Some(delegate_context_data),
1274 processed: request.processed,
1275 },
1276 );
1277 let msg = FbsOutboundDelegateMsg::create(
1278 &mut builder,
1279 &OutboundDelegateMsgArgs {
1280 inbound_type: OutboundDelegateMsgType::common_GetSecretRequest,
1281 inbound: Some(request_offset.as_union_value()),
1282 },
1283 );
1284 messages.push(msg);
1285 }
1286 OutboundDelegateMsg::SetSecretRequest(request) => {
1287 let secret_key_data = builder.create_vector(request.key.key());
1288 let secret_hash_data = builder.create_vector(request.key.hash());
1289 let secret_id_offset = FbsSecretsId::create(
1290 &mut builder,
1291 &SecretsIdArgs {
1292 key: Some(secret_key_data),
1293 hash: Some(secret_hash_data),
1294 },
1295 );
1296
1297 let value_data = request
1298 .value
1299 .clone()
1300 .map(|value| builder.create_vector(value.as_slice()));
1301 let request_offset = FbsSetSecretRequest::create(
1302 &mut builder,
1303 &SetSecretRequestArgs {
1304 key: Some(secret_id_offset),
1305 value: value_data,
1306 },
1307 );
1308 let msg = FbsOutboundDelegateMsg::create(
1309 &mut builder,
1310 &OutboundDelegateMsgArgs {
1311 inbound_type: OutboundDelegateMsgType::SetSecretRequest,
1312 inbound: Some(request_offset.as_union_value()),
1313 },
1314 );
1315 messages.push(msg);
1316 }
1317 OutboundDelegateMsg::GetSecretResponse(response) => {
1318 let secret_key_data = builder.create_vector(response.key.key());
1319 let secret_hash_data = builder.create_vector(response.key.hash());
1320 let secret_id_offset = FbsSecretsId::create(
1321 &mut builder,
1322 &SecretsIdArgs {
1323 key: Some(secret_key_data),
1324 hash: Some(secret_hash_data),
1325 },
1326 );
1327
1328 let value_data = response
1329 .value
1330 .clone()
1331 .map(|value| builder.create_vector(value.as_slice()));
1332
1333 let delegate_context_data =
1334 builder.create_vector(response.context.as_ref());
1335 let response_offset = FbsGetSecretResponse::create(
1336 &mut builder,
1337 &GetSecretResponseArgs {
1338 key: Some(secret_id_offset),
1339 value: value_data,
1340 delegate_context: Some(delegate_context_data),
1341 },
1342 );
1343 let msg = FbsOutboundDelegateMsg::create(
1344 &mut builder,
1345 &OutboundDelegateMsgArgs {
1346 inbound_type: OutboundDelegateMsgType::common_GetSecretResponse,
1347 inbound: Some(response_offset.as_union_value()),
1348 },
1349 );
1350 messages.push(msg);
1351 }
1352 });
1353 let messages_offset = builder.create_vector(&messages);
1354 let delegate_response_offset = FbsDelegateResponse::create(
1355 &mut builder,
1356 &DelegateResponseArgs {
1357 key: Some(key_offset),
1358 values: Some(messages_offset),
1359 },
1360 );
1361 let host_response_offset = FbsHostResponse::create(
1362 &mut builder,
1363 &HostResponseArgs {
1364 response_type: HostResponseType::DelegateResponse,
1365 response: Some(delegate_response_offset.as_union_value()),
1366 },
1367 );
1368 finish_host_response_buffer(&mut builder, host_response_offset);
1369 Ok(builder.finished_data().to_vec())
1370 }
1371 HostResponse::Ok => {
1372 let ok_offset = FbsOk::create(&mut builder, &OkArgs { msg: None });
1373 let host_response_offset = FbsHostResponse::create(
1374 &mut builder,
1375 &HostResponseArgs {
1376 response_type: HostResponseType::Ok,
1377 response: Some(ok_offset.as_union_value()),
1378 },
1379 );
1380 finish_host_response_buffer(&mut builder, host_response_offset);
1381 Ok(builder.finished_data().to_vec())
1382 }
1383 HostResponse::QueryResponse(_) => unimplemented!(),
1384 }
1385 }
1386}
1387
1388impl Display for HostResponse {
1389 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1390 match self {
1391 HostResponse::ContractResponse(res) => match res {
1392 ContractResponse::PutResponse { key } => {
1393 f.write_fmt(format_args!("put response for `{key}`"))
1394 }
1395 ContractResponse::UpdateResponse { key, .. } => {
1396 f.write_fmt(format_args!("update response for `{key}`"))
1397 }
1398 ContractResponse::GetResponse { key, .. } => {
1399 f.write_fmt(format_args!("get response for `{key}`"))
1400 }
1401 ContractResponse::UpdateNotification { key, .. } => {
1402 f.write_fmt(format_args!("update notification for `{key}`"))
1403 }
1404 ContractResponse::SubscribeResponse { key, .. } => {
1405 f.write_fmt(format_args!("subscribe response for `{key}`"))
1406 }
1407 },
1408 HostResponse::DelegateResponse { .. } => write!(f, "delegate responses"),
1409 HostResponse::Ok => write!(f, "ok response"),
1410 HostResponse::QueryResponse(_) => write!(f, "query response"),
1411 }
1412 }
1413}
1414
1415#[derive(Clone, Serialize, Deserialize, Debug)]
1416#[non_exhaustive]
1417pub enum ContractResponse<T = WrappedState> {
1418 GetResponse {
1419 key: ContractKey,
1420 contract: Option<ContractContainer>,
1421 #[serde(bound(deserialize = "T: DeserializeOwned"))]
1422 state: T,
1423 },
1424 PutResponse {
1425 key: ContractKey,
1426 },
1427 UpdateNotification {
1429 key: ContractKey,
1430 #[serde(deserialize_with = "UpdateData::deser_update_data")]
1431 update: UpdateData<'static>,
1432 },
1433 UpdateResponse {
1435 key: ContractKey,
1436 #[serde(deserialize_with = "StateSummary::deser_state_summary")]
1437 summary: StateSummary<'static>,
1438 },
1439 SubscribeResponse {
1440 key: ContractKey,
1441 subscribed: bool,
1442 },
1443}
1444
1445impl<T> From<ContractResponse<T>> for HostResponse<T> {
1446 fn from(value: ContractResponse<T>) -> HostResponse<T> {
1447 HostResponse::ContractResponse(value)
1448 }
1449}
1450
1451#[cfg(test)]
1452mod client_request_test {
1453 use crate::client_api::{ContractRequest, TryFromFbs};
1454 use crate::contract_interface::UpdateData;
1455 use crate::generated::client_request::root_as_client_request;
1456
1457 const EXPECTED_ENCODED_CONTRACT_ID: &str = "6kVs66bKaQAC6ohr8b43SvJ95r36tc2hnG7HezmaJHF9";
1458
1459 #[test]
1460 fn test_build_contract_put_op_from_fbs() -> Result<(), Box<dyn std::error::Error>> {
1461 let put_req_op = vec![
1462 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,
1463 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,
1464 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,
1465 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,
1466 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,
1467 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,
1468 85, 111, 11, 171, 40, 85, 240, 177, 207, 81, 106, 157, 173, 90, 234, 2, 250, 253, 75,
1469 210, 62, 7, 6, 34, 75, 26, 229, 230, 107, 167, 17, 108, 8, 0, 0, 0, 1, 2, 3, 4, 5, 6,
1470 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,
1471 3, 4, 5, 6, 7, 8, 8, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8,
1472 ];
1473 let request = if let Ok(client_request) = root_as_client_request(&put_req_op) {
1474 let contract_request = client_request.client_request_as_contract_request().unwrap();
1475 ContractRequest::try_decode_fbs(&contract_request)?
1476 } else {
1477 panic!("failed to decode client request")
1478 };
1479
1480 match request {
1481 ContractRequest::Put {
1482 contract,
1483 state,
1484 related_contracts: _,
1485 subscribe,
1486 } => {
1487 assert_eq!(
1488 contract.to_string(),
1489 "WasmContainer([api=0.0.1](D8fdVLbRyMLw5mZtPRpWMFcrXGN2z8Nq8UGcLGPFBg2W))"
1490 );
1491 assert_eq!(contract.unwrap_v1().data.data(), &[1, 2, 3, 4, 5, 6, 7, 8]);
1492 assert_eq!(state.to_vec(), &[1, 2, 3, 4, 5, 6, 7, 8]);
1493 assert!(!subscribe);
1494 }
1495 _ => panic!("wrong contract request type"),
1496 }
1497
1498 Ok(())
1499 }
1500
1501 #[test]
1502 fn test_build_contract_get_op_from_fbs() -> Result<(), Box<dyn std::error::Error>> {
1503 let get_req_op = vec![
1504 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,
1505 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,
1506 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,
1507 4, 0, 0, 0, 32, 0, 0, 0, 85, 111, 11, 171, 40, 85, 240, 177, 207, 81, 106, 157, 173,
1508 90, 234, 2, 250, 253, 75, 210, 62, 7, 6, 34, 75, 26, 229, 230, 107, 167, 17, 108,
1509 ];
1510 let request = if let Ok(client_request) = root_as_client_request(&get_req_op) {
1511 let contract_request = client_request.client_request_as_contract_request().unwrap();
1512 ContractRequest::try_decode_fbs(&contract_request)?
1513 } else {
1514 panic!("failed to decode client request")
1515 };
1516
1517 match request {
1518 ContractRequest::Get {
1519 key,
1520 return_contract_code: fetch_contract,
1521 subscribe,
1522 } => {
1523 assert_eq!(key.encoded_contract_id(), EXPECTED_ENCODED_CONTRACT_ID);
1524 assert!(!fetch_contract);
1525 assert!(!subscribe);
1526 }
1527 _ => panic!("wrong contract request type"),
1528 }
1529
1530 Ok(())
1531 }
1532
1533 #[test]
1534 fn test_build_contract_update_op_from_fbs() -> Result<(), Box<dyn std::error::Error>> {
1535 let update_op = vec![
1536 4, 0, 0, 0, 220, 255, 255, 255, 8, 0, 0, 0, 0, 0, 0, 1, 232, 255, 255, 255, 8, 0, 0, 0,
1537 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,
1538 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,
1539 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,
1540 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,
1541 85, 240, 177, 207, 81, 106, 157, 173, 90, 234, 2, 250, 253, 75, 210, 62, 7, 6, 34, 75,
1542 26, 229, 230, 107, 167, 17, 108,
1543 ];
1544 let request = if let Ok(client_request) = root_as_client_request(&update_op) {
1545 let contract_request = client_request.client_request_as_contract_request().unwrap();
1546 ContractRequest::try_decode_fbs(&contract_request)?
1547 } else {
1548 panic!("failed to decode client request")
1549 };
1550
1551 match request {
1552 ContractRequest::Update { key, data } => {
1553 assert_eq!(
1554 key.encoded_contract_id(),
1555 "6kVs66bKaQAC6ohr8b43SvJ95r36tc2hnG7HezmaJHF9"
1556 );
1557 match data {
1558 UpdateData::Delta(delta) => {
1559 assert_eq!(delta.to_vec(), &[1, 2, 3, 4, 5, 6, 7, 8])
1560 }
1561 _ => panic!("wrong update data type"),
1562 }
1563 }
1564 _ => panic!("wrong contract request type"),
1565 }
1566
1567 Ok(())
1568 }
1569}