1use std::{
2 borrow::{Borrow, Cow},
3 fmt::Display,
4 fs::File,
5 io::Read,
6 ops::Deref,
7 path::Path,
8};
9
10use blake3::{traits::digest::Digest, Hasher as Blake3};
11use serde::{Deserialize, Deserializer, Serialize};
12use serde_with::serde_as;
13
14use crate::generated::client_request::{
15 DelegateKey as FbsDelegateKey, InboundDelegateMsg as FbsInboundDelegateMsg,
16 InboundDelegateMsgType,
17};
18
19use crate::common_generated::common::SecretsId as FbsSecretsId;
20
21use crate::client_api::{TryFromFbs, WsApiError};
22use crate::contract_interface::{RelatedContracts, UpdateData};
23use crate::prelude::{ContractInstanceId, WrappedState};
24use crate::versioning::ContractContainer;
25use crate::{code_hash::CodeHash, prelude::Parameters};
26
27const DELEGATE_HASH_LENGTH: usize = 32;
28
29#[derive(Clone, Debug, Serialize, Deserialize)]
30pub struct Delegate<'a> {
31 #[serde(borrow)]
32 parameters: Parameters<'a>,
33 #[serde(borrow)]
34 pub data: DelegateCode<'a>,
35 key: DelegateKey,
36}
37
38impl Delegate<'_> {
39 pub fn key(&self) -> &DelegateKey {
40 &self.key
41 }
42
43 pub fn code(&self) -> &DelegateCode<'_> {
44 &self.data
45 }
46
47 pub fn code_hash(&self) -> &CodeHash {
48 &self.data.code_hash
49 }
50
51 pub fn params(&self) -> &Parameters<'_> {
52 &self.parameters
53 }
54
55 pub fn into_owned(self) -> Delegate<'static> {
56 Delegate {
57 parameters: self.parameters.into_owned(),
58 data: self.data.into_owned(),
59 key: self.key,
60 }
61 }
62
63 pub fn size(&self) -> usize {
64 self.parameters.size() + self.data.size()
65 }
66
67 pub(crate) fn deserialize_delegate<'de, D>(deser: D) -> Result<Delegate<'static>, D::Error>
68 where
69 D: Deserializer<'de>,
70 {
71 let data: Delegate<'de> = Deserialize::deserialize(deser)?;
72 Ok(data.into_owned())
73 }
74}
75
76impl PartialEq for Delegate<'_> {
77 fn eq(&self, other: &Self) -> bool {
78 self.key == other.key
79 }
80}
81
82impl Eq for Delegate<'_> {}
83
84impl<'a> From<(&DelegateCode<'a>, &Parameters<'a>)> for Delegate<'a> {
85 fn from((data, parameters): (&DelegateCode<'a>, &Parameters<'a>)) -> Self {
86 Self {
87 key: DelegateKey::from_params_and_code(parameters, data),
88 parameters: parameters.clone(),
89 data: data.clone(),
90 }
91 }
92}
93
94#[derive(Debug, Serialize, Deserialize, Clone)]
96#[serde_as]
97pub struct DelegateCode<'a> {
98 #[serde_as(as = "serde_with::Bytes")]
99 #[serde(borrow)]
100 pub(crate) data: Cow<'a, [u8]>,
101 pub(crate) code_hash: CodeHash,
103}
104
105impl DelegateCode<'static> {
106 pub fn load_raw(path: &Path) -> Result<Self, std::io::Error> {
108 let contract_data = Self::load_bytes(path)?;
109 Ok(DelegateCode::from(contract_data))
110 }
111
112 pub(crate) fn load_bytes(path: &Path) -> Result<Vec<u8>, std::io::Error> {
113 let mut contract_file = File::open(path)?;
114 let mut contract_data = if let Ok(md) = contract_file.metadata() {
115 Vec::with_capacity(md.len() as usize)
116 } else {
117 Vec::new()
118 };
119 contract_file.read_to_end(&mut contract_data)?;
120 Ok(contract_data)
121 }
122}
123
124impl DelegateCode<'_> {
125 pub fn hash(&self) -> &CodeHash {
127 &self.code_hash
128 }
129
130 pub fn hash_str(&self) -> String {
132 Self::encode_hash(&self.code_hash.0)
133 }
134
135 pub fn data(&self) -> &[u8] {
137 &self.data
138 }
139
140 pub fn encode_hash(hash: &[u8; DELEGATE_HASH_LENGTH]) -> String {
142 bs58::encode(hash)
143 .with_alphabet(bs58::Alphabet::BITCOIN)
144 .into_string()
145 }
146
147 pub fn into_owned(self) -> DelegateCode<'static> {
148 DelegateCode {
149 code_hash: self.code_hash,
150 data: Cow::from(self.data.into_owned()),
151 }
152 }
153
154 pub fn size(&self) -> usize {
155 self.data.len()
156 }
157}
158
159impl PartialEq for DelegateCode<'_> {
160 fn eq(&self, other: &Self) -> bool {
161 self.code_hash == other.code_hash
162 }
163}
164
165impl Eq for DelegateCode<'_> {}
166
167impl AsRef<[u8]> for DelegateCode<'_> {
168 fn as_ref(&self) -> &[u8] {
169 self.data.borrow()
170 }
171}
172
173impl From<Vec<u8>> for DelegateCode<'static> {
174 fn from(data: Vec<u8>) -> Self {
175 let key = CodeHash::from_code(data.as_slice());
176 DelegateCode {
177 data: Cow::from(data),
178 code_hash: key,
179 }
180 }
181}
182
183impl<'a> From<&'a [u8]> for DelegateCode<'a> {
184 fn from(code: &'a [u8]) -> Self {
185 let key = CodeHash::from_code(code);
186 DelegateCode {
187 data: Cow::from(code),
188 code_hash: key,
189 }
190 }
191}
192
193#[serde_as]
194#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
195pub struct DelegateKey {
196 #[serde_as(as = "[_; DELEGATE_HASH_LENGTH]")]
197 key: [u8; DELEGATE_HASH_LENGTH],
198 code_hash: CodeHash,
199}
200
201impl From<DelegateKey> for SecretsId {
202 fn from(key: DelegateKey) -> SecretsId {
203 SecretsId {
204 hash: key.key,
205 key: vec![],
206 }
207 }
208}
209
210impl DelegateKey {
211 pub const fn new(key: [u8; DELEGATE_HASH_LENGTH], code_hash: CodeHash) -> Self {
212 Self { key, code_hash }
213 }
214
215 fn from_params_and_code<'a>(
216 params: impl Borrow<Parameters<'a>>,
217 wasm_code: impl Borrow<DelegateCode<'a>>,
218 ) -> Self {
219 let code = wasm_code.borrow();
220 let key = generate_id(params.borrow(), code);
221 Self {
222 key,
223 code_hash: *code.hash(),
224 }
225 }
226
227 pub fn encode(&self) -> String {
228 bs58::encode(self.key)
229 .with_alphabet(bs58::Alphabet::BITCOIN)
230 .into_string()
231 }
232
233 pub fn code_hash(&self) -> &CodeHash {
234 &self.code_hash
235 }
236
237 pub fn bytes(&self) -> &[u8] {
238 self.key.as_ref()
239 }
240
241 pub fn from_params(
242 code_hash: impl Into<String>,
243 parameters: &Parameters,
244 ) -> Result<Self, bs58::decode::Error> {
245 let mut code_key = [0; DELEGATE_HASH_LENGTH];
246 bs58::decode(code_hash.into())
247 .with_alphabet(bs58::Alphabet::BITCOIN)
248 .onto(&mut code_key)?;
249 let mut hasher = Blake3::new();
250 hasher.update(code_key.as_slice());
251 hasher.update(parameters.as_ref());
252 let full_key_arr = hasher.finalize();
253
254 debug_assert_eq!(full_key_arr[..].len(), DELEGATE_HASH_LENGTH);
255 let mut key = [0; DELEGATE_HASH_LENGTH];
256 key.copy_from_slice(&full_key_arr);
257
258 Ok(Self {
259 key,
260 code_hash: CodeHash(code_key),
261 })
262 }
263}
264
265impl Deref for DelegateKey {
266 type Target = [u8; DELEGATE_HASH_LENGTH];
267
268 fn deref(&self) -> &Self::Target {
269 &self.key
270 }
271}
272
273impl Display for DelegateKey {
274 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
275 write!(f, "{}", self.encode())
276 }
277}
278
279impl<'a> TryFromFbs<&FbsDelegateKey<'a>> for DelegateKey {
280 fn try_decode_fbs(key: &FbsDelegateKey<'a>) -> Result<Self, WsApiError> {
281 let mut key_bytes = [0; DELEGATE_HASH_LENGTH];
282 key_bytes.copy_from_slice(key.key().bytes());
283 let code_hash = CodeHash::try_from(key.code_hash().bytes())
284 .map_err(|e| WsApiError::deserialization(e.to_string()))?;
285 Ok(DelegateKey {
286 key: key_bytes,
287 code_hash,
288 })
289 }
290}
291
292#[non_exhaustive]
297#[derive(Debug, thiserror::Error, Serialize, Deserialize)]
298pub enum DelegateError {
299 #[error("de/serialization error: {0}")]
300 Deser(String),
301 #[error("{0}")]
302 Other(String),
303}
304
305fn generate_id<'a>(
306 parameters: &Parameters<'a>,
307 code_data: &DelegateCode<'a>,
308) -> [u8; DELEGATE_HASH_LENGTH] {
309 let contract_hash = code_data.hash();
310
311 let mut hasher = Blake3::new();
312 hasher.update(contract_hash.0.as_slice());
313 hasher.update(parameters.as_ref());
314 let full_key_arr = hasher.finalize();
315
316 debug_assert_eq!(full_key_arr[..].len(), DELEGATE_HASH_LENGTH);
317 let mut key = [0; DELEGATE_HASH_LENGTH];
318 key.copy_from_slice(&full_key_arr);
319 key
320}
321
322#[serde_as]
323#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
324pub struct SecretsId {
325 #[serde_as(as = "serde_with::Bytes")]
326 key: Vec<u8>,
327 #[serde_as(as = "[_; 32]")]
328 hash: [u8; 32],
329}
330
331impl SecretsId {
332 pub fn new(key: Vec<u8>) -> Self {
333 let mut hasher = Blake3::new();
334 hasher.update(&key);
335 let hashed = hasher.finalize();
336 let mut hash = [0; 32];
337 hash.copy_from_slice(&hashed);
338 Self { key, hash }
339 }
340
341 pub fn encode(&self) -> String {
342 bs58::encode(self.hash)
343 .with_alphabet(bs58::Alphabet::BITCOIN)
344 .into_string()
345 }
346
347 pub fn hash(&self) -> &[u8; 32] {
348 &self.hash
349 }
350 pub fn key(&self) -> &[u8] {
351 self.key.as_slice()
352 }
353}
354
355impl Display for SecretsId {
356 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
357 write!(f, "{}", self.encode())
358 }
359}
360
361impl<'a> TryFromFbs<&FbsSecretsId<'a>> for SecretsId {
362 fn try_decode_fbs(key: &FbsSecretsId<'a>) -> Result<Self, WsApiError> {
363 let mut key_hash = [0; 32];
364 key_hash.copy_from_slice(key.hash().bytes().iter().as_ref());
365 Ok(SecretsId {
366 key: key.key().bytes().to_vec(),
367 hash: key_hash,
368 })
369 }
370}
371
372#[non_exhaustive]
386#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
387pub enum MessageOrigin {
388 WebApp(ContractInstanceId),
390 Delegate(DelegateKey),
402}
403
404pub trait DelegateInterface {
449 fn process(
460 ctx: &mut crate::delegate_host::DelegateCtx,
461 parameters: Parameters<'static>,
462 origin: Option<MessageOrigin>,
463 message: InboundDelegateMsg,
464 ) -> Result<Vec<OutboundDelegateMsg>, DelegateError>;
465}
466
467#[serde_as]
468#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
469pub struct DelegateContext(#[serde_as(as = "serde_with::Bytes")] Vec<u8>);
470
471impl DelegateContext {
472 pub const MAX_SIZE: usize = 4096 * 10 * 10;
473
474 pub fn new(bytes: Vec<u8>) -> Self {
475 assert!(bytes.len() < Self::MAX_SIZE);
476 Self(bytes)
477 }
478
479 pub fn append(&mut self, bytes: &mut Vec<u8>) {
480 assert!(self.0.len() + bytes.len() < Self::MAX_SIZE);
481 self.0.append(bytes)
482 }
483
484 pub fn replace(&mut self, bytes: Vec<u8>) {
485 assert!(bytes.len() < Self::MAX_SIZE);
486 let _ = std::mem::replace(&mut self.0, bytes);
487 }
488}
489
490impl AsRef<[u8]> for DelegateContext {
491 fn as_ref(&self) -> &[u8] {
492 &self.0
493 }
494}
495
496#[non_exhaustive]
508#[derive(Serialize, Deserialize, Debug, Clone)]
509pub enum InboundDelegateMsg<'a> {
510 ApplicationMessage(ApplicationMessage),
511 UserResponse(#[serde(borrow)] UserInputResponse<'a>),
512 GetContractResponse(GetContractResponse),
513 PutContractResponse(PutContractResponse),
514 UpdateContractResponse(UpdateContractResponse),
515 SubscribeContractResponse(SubscribeContractResponse),
516 ContractNotification(ContractNotification),
517 DelegateMessage(DelegateMessage),
518}
519
520impl InboundDelegateMsg<'_> {
521 pub fn into_owned(self) -> InboundDelegateMsg<'static> {
522 match self {
523 InboundDelegateMsg::ApplicationMessage(r) => InboundDelegateMsg::ApplicationMessage(r),
524 InboundDelegateMsg::UserResponse(r) => InboundDelegateMsg::UserResponse(r.into_owned()),
525 InboundDelegateMsg::GetContractResponse(r) => {
526 InboundDelegateMsg::GetContractResponse(r)
527 }
528 InboundDelegateMsg::PutContractResponse(r) => {
529 InboundDelegateMsg::PutContractResponse(r)
530 }
531 InboundDelegateMsg::UpdateContractResponse(r) => {
532 InboundDelegateMsg::UpdateContractResponse(r)
533 }
534 InboundDelegateMsg::SubscribeContractResponse(r) => {
535 InboundDelegateMsg::SubscribeContractResponse(r)
536 }
537 InboundDelegateMsg::ContractNotification(r) => {
538 InboundDelegateMsg::ContractNotification(r)
539 }
540 InboundDelegateMsg::DelegateMessage(r) => InboundDelegateMsg::DelegateMessage(r),
541 }
542 }
543
544 pub fn get_context(&self) -> Option<&DelegateContext> {
545 match self {
546 InboundDelegateMsg::ApplicationMessage(ApplicationMessage { context, .. }) => {
547 Some(context)
548 }
549 InboundDelegateMsg::GetContractResponse(GetContractResponse { context, .. }) => {
550 Some(context)
551 }
552 InboundDelegateMsg::PutContractResponse(PutContractResponse { context, .. }) => {
553 Some(context)
554 }
555 InboundDelegateMsg::UpdateContractResponse(UpdateContractResponse {
556 context, ..
557 }) => Some(context),
558 InboundDelegateMsg::SubscribeContractResponse(SubscribeContractResponse {
559 context,
560 ..
561 }) => Some(context),
562 InboundDelegateMsg::ContractNotification(ContractNotification { context, .. }) => {
563 Some(context)
564 }
565 InboundDelegateMsg::DelegateMessage(DelegateMessage { context, .. }) => Some(context),
566 _ => None,
567 }
568 }
569
570 pub fn get_mut_context(&mut self) -> Option<&mut DelegateContext> {
571 match self {
572 InboundDelegateMsg::ApplicationMessage(ApplicationMessage { context, .. }) => {
573 Some(context)
574 }
575 InboundDelegateMsg::GetContractResponse(GetContractResponse { context, .. }) => {
576 Some(context)
577 }
578 InboundDelegateMsg::PutContractResponse(PutContractResponse { context, .. }) => {
579 Some(context)
580 }
581 InboundDelegateMsg::UpdateContractResponse(UpdateContractResponse {
582 context, ..
583 }) => Some(context),
584 InboundDelegateMsg::SubscribeContractResponse(SubscribeContractResponse {
585 context,
586 ..
587 }) => Some(context),
588 InboundDelegateMsg::ContractNotification(ContractNotification { context, .. }) => {
589 Some(context)
590 }
591 InboundDelegateMsg::DelegateMessage(DelegateMessage { context, .. }) => Some(context),
592 _ => None,
593 }
594 }
595}
596
597impl From<ApplicationMessage> for InboundDelegateMsg<'_> {
598 fn from(value: ApplicationMessage) -> Self {
599 Self::ApplicationMessage(value)
600 }
601}
602
603impl<'a> TryFromFbs<&FbsInboundDelegateMsg<'a>> for InboundDelegateMsg<'a> {
604 fn try_decode_fbs(msg: &FbsInboundDelegateMsg<'a>) -> Result<Self, WsApiError> {
605 match msg.inbound_type() {
606 InboundDelegateMsgType::common_ApplicationMessage => {
607 let app_msg = msg.inbound_as_common_application_message().unwrap();
608 let app_msg = ApplicationMessage {
609 payload: app_msg.payload().bytes().to_vec(),
610 context: DelegateContext::new(app_msg.context().bytes().to_vec()),
611 processed: app_msg.processed(),
612 };
613 Ok(InboundDelegateMsg::ApplicationMessage(app_msg))
614 }
615 InboundDelegateMsgType::UserInputResponse => {
616 let user_response = msg.inbound_as_user_input_response().unwrap();
617 let user_response = UserInputResponse {
618 request_id: user_response.request_id(),
619 response: ClientResponse::new(user_response.response().data().bytes().to_vec()),
620 context: DelegateContext::new(
621 user_response.delegate_context().bytes().to_vec(),
622 ),
623 };
624 Ok(InboundDelegateMsg::UserResponse(user_response))
625 }
626 _ => unreachable!("invalid inbound delegate message type"),
627 }
628 }
629}
630
631#[non_exhaustive]
632#[derive(Serialize, Deserialize, Debug, Clone)]
633pub struct ApplicationMessage {
634 pub payload: Vec<u8>,
635 pub context: DelegateContext,
636 pub processed: bool,
637}
638
639impl ApplicationMessage {
640 pub fn new(payload: Vec<u8>) -> Self {
641 Self {
642 payload,
643 context: DelegateContext::default(),
644 processed: false,
645 }
646 }
647
648 pub fn with_context(mut self, context: DelegateContext) -> Self {
649 self.context = context;
650 self
651 }
652
653 pub fn processed(mut self, p: bool) -> Self {
654 self.processed = p;
655 self
656 }
657}
658
659#[derive(Serialize, Deserialize, Debug, Clone)]
660pub struct UserInputResponse<'a> {
661 pub request_id: u32,
662 #[serde(borrow)]
663 pub response: ClientResponse<'a>,
664 pub context: DelegateContext,
665}
666
667impl UserInputResponse<'_> {
668 pub fn into_owned(self) -> UserInputResponse<'static> {
669 UserInputResponse {
670 request_id: self.request_id,
671 response: self.response.into_owned(),
672 context: self.context,
673 }
674 }
675}
676
677#[derive(Serialize, Deserialize, Debug, Clone)]
678pub enum OutboundDelegateMsg {
679 ApplicationMessage(ApplicationMessage),
681 RequestUserInput(
682 #[serde(deserialize_with = "OutboundDelegateMsg::deser_user_input_req")]
683 UserInputRequest<'static>,
684 ),
685 ContextUpdated(DelegateContext),
687 GetContractRequest(GetContractRequest),
688 PutContractRequest(PutContractRequest),
689 UpdateContractRequest(UpdateContractRequest),
690 SubscribeContractRequest(SubscribeContractRequest),
691 SendDelegateMessage(DelegateMessage),
692}
693
694impl From<ApplicationMessage> for OutboundDelegateMsg {
695 fn from(req: ApplicationMessage) -> Self {
696 Self::ApplicationMessage(req)
697 }
698}
699
700impl From<GetContractRequest> for OutboundDelegateMsg {
701 fn from(req: GetContractRequest) -> Self {
702 Self::GetContractRequest(req)
703 }
704}
705
706impl From<PutContractRequest> for OutboundDelegateMsg {
707 fn from(req: PutContractRequest) -> Self {
708 Self::PutContractRequest(req)
709 }
710}
711
712impl From<UpdateContractRequest> for OutboundDelegateMsg {
713 fn from(req: UpdateContractRequest) -> Self {
714 Self::UpdateContractRequest(req)
715 }
716}
717
718impl From<SubscribeContractRequest> for OutboundDelegateMsg {
719 fn from(req: SubscribeContractRequest) -> Self {
720 Self::SubscribeContractRequest(req)
721 }
722}
723
724impl From<DelegateMessage> for OutboundDelegateMsg {
725 fn from(msg: DelegateMessage) -> Self {
726 Self::SendDelegateMessage(msg)
727 }
728}
729
730impl OutboundDelegateMsg {
731 fn deser_user_input_req<'de, D>(deser: D) -> Result<UserInputRequest<'static>, D::Error>
732 where
733 D: serde::Deserializer<'de>,
734 {
735 let value = <UserInputRequest<'de> as Deserialize>::deserialize(deser)?;
736 Ok(value.into_owned())
737 }
738
739 pub fn processed(&self) -> bool {
740 match self {
741 OutboundDelegateMsg::ApplicationMessage(msg) => msg.processed,
742 OutboundDelegateMsg::GetContractRequest(msg) => msg.processed,
743 OutboundDelegateMsg::PutContractRequest(msg) => msg.processed,
744 OutboundDelegateMsg::UpdateContractRequest(msg) => msg.processed,
745 OutboundDelegateMsg::SubscribeContractRequest(msg) => msg.processed,
746 OutboundDelegateMsg::SendDelegateMessage(msg) => msg.processed,
747 OutboundDelegateMsg::RequestUserInput(_) => true,
748 OutboundDelegateMsg::ContextUpdated(_) => true,
749 }
750 }
751
752 pub fn get_context(&self) -> Option<&DelegateContext> {
753 match self {
754 OutboundDelegateMsg::ApplicationMessage(ApplicationMessage { context, .. }) => {
755 Some(context)
756 }
757 OutboundDelegateMsg::GetContractRequest(GetContractRequest { context, .. }) => {
758 Some(context)
759 }
760 OutboundDelegateMsg::PutContractRequest(PutContractRequest { context, .. }) => {
761 Some(context)
762 }
763 OutboundDelegateMsg::UpdateContractRequest(UpdateContractRequest {
764 context, ..
765 }) => Some(context),
766 OutboundDelegateMsg::SubscribeContractRequest(SubscribeContractRequest {
767 context,
768 ..
769 }) => Some(context),
770 OutboundDelegateMsg::SendDelegateMessage(DelegateMessage { context, .. }) => {
771 Some(context)
772 }
773 _ => None,
774 }
775 }
776
777 pub fn get_mut_context(&mut self) -> Option<&mut DelegateContext> {
778 match self {
779 OutboundDelegateMsg::ApplicationMessage(ApplicationMessage { context, .. }) => {
780 Some(context)
781 }
782 OutboundDelegateMsg::GetContractRequest(GetContractRequest { context, .. }) => {
783 Some(context)
784 }
785 OutboundDelegateMsg::PutContractRequest(PutContractRequest { context, .. }) => {
786 Some(context)
787 }
788 OutboundDelegateMsg::UpdateContractRequest(UpdateContractRequest {
789 context, ..
790 }) => Some(context),
791 OutboundDelegateMsg::SubscribeContractRequest(SubscribeContractRequest {
792 context,
793 ..
794 }) => Some(context),
795 OutboundDelegateMsg::SendDelegateMessage(DelegateMessage { context, .. }) => {
796 Some(context)
797 }
798 _ => None,
799 }
800 }
801}
802
803#[derive(Serialize, Deserialize, Debug, Clone)]
805pub struct GetContractRequest {
806 pub contract_id: ContractInstanceId,
807 pub context: DelegateContext,
808 pub processed: bool,
809}
810
811impl GetContractRequest {
812 pub fn new(contract_id: ContractInstanceId) -> Self {
813 Self {
814 contract_id,
815 context: Default::default(),
816 processed: false,
817 }
818 }
819}
820
821#[derive(Serialize, Deserialize, Debug, Clone)]
823pub struct GetContractResponse {
824 pub contract_id: ContractInstanceId,
825 pub state: Option<WrappedState>,
827 pub context: DelegateContext,
828}
829
830#[derive(Serialize, Deserialize, Debug, Clone)]
832pub struct PutContractRequest {
833 pub contract: ContractContainer,
835 pub state: WrappedState,
837 #[serde(deserialize_with = "RelatedContracts::deser_related_contracts")]
839 pub related_contracts: RelatedContracts<'static>,
840 pub context: DelegateContext,
842 pub processed: bool,
844}
845
846impl PutContractRequest {
847 pub fn new(
848 contract: ContractContainer,
849 state: WrappedState,
850 related_contracts: RelatedContracts<'static>,
851 ) -> Self {
852 Self {
853 contract,
854 state,
855 related_contracts,
856 context: Default::default(),
857 processed: false,
858 }
859 }
860}
861
862#[derive(Serialize, Deserialize, Debug, Clone)]
864pub struct PutContractResponse {
865 pub contract_id: ContractInstanceId,
867 pub result: Result<(), String>,
869 pub context: DelegateContext,
871}
872
873#[derive(Serialize, Deserialize, Debug, Clone)]
875pub struct UpdateContractRequest {
876 pub contract_id: ContractInstanceId,
878 #[serde(deserialize_with = "UpdateContractRequest::deser_update_data")]
880 pub update: UpdateData<'static>,
881 pub context: DelegateContext,
883 pub processed: bool,
885}
886
887impl UpdateContractRequest {
888 pub fn new(contract_id: ContractInstanceId, update: UpdateData<'static>) -> Self {
889 Self {
890 contract_id,
891 update,
892 context: Default::default(),
893 processed: false,
894 }
895 }
896
897 fn deser_update_data<'de, D>(deser: D) -> Result<UpdateData<'static>, D::Error>
898 where
899 D: Deserializer<'de>,
900 {
901 let value = <UpdateData<'de> as Deserialize>::deserialize(deser)?;
902 Ok(value.into_owned())
903 }
904}
905
906#[derive(Serialize, Deserialize, Debug, Clone)]
908pub struct UpdateContractResponse {
909 pub contract_id: ContractInstanceId,
911 pub result: Result<(), String>,
913 pub context: DelegateContext,
915}
916
917#[derive(Serialize, Deserialize, Debug, Clone)]
919pub struct SubscribeContractRequest {
920 pub contract_id: ContractInstanceId,
922 pub context: DelegateContext,
924 pub processed: bool,
926}
927
928impl SubscribeContractRequest {
929 pub fn new(contract_id: ContractInstanceId) -> Self {
930 Self {
931 contract_id,
932 context: Default::default(),
933 processed: false,
934 }
935 }
936}
937
938#[derive(Serialize, Deserialize, Debug, Clone)]
940pub struct SubscribeContractResponse {
941 pub contract_id: ContractInstanceId,
943 pub result: Result<(), String>,
945 pub context: DelegateContext,
947}
948
949#[derive(Serialize, Deserialize, Debug, Clone)]
959pub struct DelegateMessage {
960 pub target: DelegateKey,
962 pub sender: DelegateKey,
964 pub payload: Vec<u8>,
966 pub context: DelegateContext,
968 pub processed: bool,
970}
971
972impl DelegateMessage {
973 pub fn new(target: DelegateKey, sender: DelegateKey, payload: Vec<u8>) -> Self {
974 Self {
975 target,
976 sender,
977 payload,
978 context: DelegateContext::default(),
979 processed: false,
980 }
981 }
982}
983
984#[derive(Serialize, Deserialize, Debug, Clone)]
986pub struct ContractNotification {
987 pub contract_id: ContractInstanceId,
989 pub new_state: WrappedState,
991 pub context: DelegateContext,
993}
994
995#[serde_as]
996#[derive(Serialize, Deserialize, Debug, Clone)]
997pub struct NotificationMessage<'a>(
998 #[serde_as(as = "serde_with::Bytes")]
999 #[serde(borrow)]
1000 Cow<'a, [u8]>,
1001);
1002
1003impl TryFrom<&serde_json::Value> for NotificationMessage<'static> {
1004 type Error = ();
1005
1006 fn try_from(json: &serde_json::Value) -> Result<NotificationMessage<'static>, ()> {
1007 let bytes = serde_json::to_vec(json).unwrap();
1009 Ok(Self(Cow::Owned(bytes)))
1010 }
1011}
1012
1013impl NotificationMessage<'_> {
1014 pub fn into_owned(self) -> NotificationMessage<'static> {
1015 NotificationMessage(self.0.into_owned().into())
1016 }
1017 pub fn bytes(&self) -> &[u8] {
1018 self.0.as_ref()
1019 }
1020}
1021
1022#[serde_as]
1023#[derive(Serialize, Deserialize, Debug, Clone)]
1024pub struct ClientResponse<'a>(
1025 #[serde_as(as = "serde_with::Bytes")]
1026 #[serde(borrow)]
1027 Cow<'a, [u8]>,
1028);
1029
1030impl Deref for ClientResponse<'_> {
1031 type Target = [u8];
1032
1033 fn deref(&self) -> &Self::Target {
1034 &self.0
1035 }
1036}
1037
1038impl ClientResponse<'_> {
1039 pub fn new(response: Vec<u8>) -> Self {
1040 Self(response.into())
1041 }
1042 pub fn into_owned(self) -> ClientResponse<'static> {
1043 ClientResponse(self.0.into_owned().into())
1044 }
1045 pub fn bytes(&self) -> &[u8] {
1046 self.0.as_ref()
1047 }
1048}
1049
1050#[derive(Serialize, Deserialize, Debug, Clone)]
1051pub struct UserInputRequest<'a> {
1052 pub request_id: u32,
1053 #[serde(borrow)]
1054 pub message: NotificationMessage<'a>,
1056 pub responses: Vec<ClientResponse<'a>>,
1058}
1059
1060impl UserInputRequest<'_> {
1061 pub fn into_owned(self) -> UserInputRequest<'static> {
1062 UserInputRequest {
1063 request_id: self.request_id,
1064 message: self.message.into_owned(),
1065 responses: self.responses.into_iter().map(|r| r.into_owned()).collect(),
1066 }
1067 }
1068}
1069
1070#[doc(hidden)]
1071pub(crate) mod wasm_interface {
1072 use super::*;
1075 use crate::memory::WasmLinearMem;
1076
1077 #[repr(C)]
1078 #[derive(Debug, Clone, Copy)]
1079 pub struct DelegateInterfaceResult {
1080 ptr: i64,
1081 size: u32,
1082 }
1083
1084 impl DelegateInterfaceResult {
1085 pub unsafe fn from_raw(ptr: i64, mem: &WasmLinearMem) -> Self {
1086 let result = Box::leak(Box::from_raw(crate::memory::buf::compute_ptr(
1087 ptr as *mut Self,
1088 mem,
1089 )));
1090 #[cfg(feature = "trace")]
1091 {
1092 tracing::trace!(
1093 "got FFI result @ {ptr} ({:p}) -> {result:?}",
1094 ptr as *mut Self
1095 );
1096 }
1097 *result
1098 }
1099
1100 #[cfg(feature = "contract")]
1101 pub fn into_raw(self) -> i64 {
1102 #[cfg(feature = "trace")]
1103 {
1104 tracing::trace!("returning FFI -> {self:?}");
1105 }
1106 let ptr = Box::into_raw(Box::new(self));
1107 #[cfg(feature = "trace")]
1108 {
1109 tracing::trace!("FFI result ptr: {ptr:p} ({}i64)", ptr as i64);
1110 }
1111 ptr as _
1112 }
1113
1114 pub unsafe fn unwrap(
1115 self,
1116 mem: WasmLinearMem,
1117 ) -> Result<Vec<OutboundDelegateMsg>, DelegateError> {
1118 let ptr = crate::memory::buf::compute_ptr(self.ptr as *mut u8, &mem);
1119 let serialized = std::slice::from_raw_parts(ptr as *const u8, self.size as _);
1120 let value: Result<Vec<OutboundDelegateMsg>, DelegateError> =
1121 bincode::deserialize(serialized)
1122 .map_err(|e| DelegateError::Other(format!("{e}")))?;
1123 #[cfg(feature = "trace")]
1124 {
1125 tracing::trace!(
1126 "got result through FFI; addr: {:p} ({}i64, mapped: {ptr:p})
1127 serialized: {serialized:?}
1128 value: {value:?}",
1129 self.ptr as *mut u8,
1130 self.ptr
1131 );
1132 }
1133 value
1134 }
1135 }
1136
1137 impl From<Result<Vec<OutboundDelegateMsg>, DelegateError>> for DelegateInterfaceResult {
1138 fn from(value: Result<Vec<OutboundDelegateMsg>, DelegateError>) -> Self {
1139 let serialized = bincode::serialize(&value).unwrap();
1140 let size = serialized.len() as _;
1141 let ptr = serialized.as_ptr();
1142 #[cfg(feature = "trace")]
1143 {
1144 tracing::trace!(
1145 "sending result through FFI; addr: {ptr:p} ({}),\n serialized: {serialized:?}\n value: {value:?}",
1146 ptr as i64
1147 );
1148 }
1149 std::mem::forget(serialized);
1150 Self {
1151 ptr: ptr as i64,
1152 size,
1153 }
1154 }
1155 }
1156}
1157
1158#[cfg(test)]
1159mod message_origin_tests {
1160 use super::*;
1161
1162 #[test]
1169 fn webapp_origin_wire_format_is_stable() {
1170 let id = ContractInstanceId::new([0xABu8; 32]);
1171 let origin = MessageOrigin::WebApp(id);
1172 let encoded = bincode::serialize(&origin).unwrap();
1173
1174 let mut expected = vec![0u8, 0, 0, 0];
1177 expected.extend_from_slice(&[0xABu8; 32]);
1178 assert_eq!(encoded, expected);
1179 }
1180
1181 #[test]
1189 fn delegate_origin_wire_format_is_stable() {
1190 let key = DelegateKey::new([0x11u8; 32], crate::code_hash::CodeHash::new([0x22u8; 32]));
1191 let origin = MessageOrigin::Delegate(key);
1192 let encoded = bincode::serialize(&origin).unwrap();
1193
1194 let mut expected = vec![1u8, 0, 0, 0];
1198 expected.extend_from_slice(&[0x11u8; 32]);
1199 expected.extend_from_slice(&[0x22u8; 32]);
1200 assert_eq!(encoded, expected);
1201
1202 let decoded: MessageOrigin = bincode::deserialize(&encoded).unwrap();
1204 assert!(matches!(decoded, MessageOrigin::Delegate(_)));
1205 }
1206
1207 #[test]
1215 fn inbound_delegate_msg_wire_format_is_stable() {
1216 let msg = InboundDelegateMsg::ApplicationMessage(ApplicationMessage::new(vec![0xCC]));
1217 let encoded = bincode::serialize(&msg).unwrap();
1218 assert_eq!(
1219 encoded[..4],
1220 [0, 0, 0, 0],
1221 "ApplicationMessage must stay at variant tag 0 on the wire; \
1222 reordering InboundDelegateMsg variants is a wire-format break"
1223 );
1224 let decoded: InboundDelegateMsg<'_> = bincode::deserialize(&encoded).unwrap();
1226 assert!(matches!(decoded, InboundDelegateMsg::ApplicationMessage(_)));
1227 }
1228}