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::{fixed_size_field, unknown_union_discriminant, TryFromFbs, WsApiError};
22use crate::contract_interface::{RelatedContracts, UpdateData, CONTRACT_KEY_SIZE};
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 key_bytes =
288 fixed_size_field::<DELEGATE_HASH_LENGTH>("DelegateKey.key", key.key().bytes())?;
289 let code_hash = CodeHash::new(fixed_size_field::<CONTRACT_KEY_SIZE>(
294 "DelegateKey.code_hash",
295 key.code_hash().bytes(),
296 )?);
297 Ok(DelegateKey {
298 key: key_bytes,
299 code_hash,
300 })
301 }
302}
303
304#[non_exhaustive]
309#[derive(Debug, thiserror::Error, Serialize, Deserialize)]
310pub enum DelegateError {
311 #[error("de/serialization error: {0}")]
312 Deser(String),
313 #[error("{0}")]
314 Other(String),
315}
316
317fn generate_id<'a>(
318 parameters: &Parameters<'a>,
319 code_data: &DelegateCode<'a>,
320) -> [u8; DELEGATE_HASH_LENGTH] {
321 let contract_hash = code_data.hash();
322
323 let mut hasher = Blake3::new();
324 hasher.update(contract_hash.0.as_slice());
325 hasher.update(parameters.as_ref());
326 let full_key_arr = hasher.finalize();
327
328 debug_assert_eq!(full_key_arr[..].len(), DELEGATE_HASH_LENGTH);
329 let mut key = [0; DELEGATE_HASH_LENGTH];
330 key.copy_from_slice(&full_key_arr);
331 key
332}
333
334#[serde_as]
335#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
336pub struct SecretsId {
337 #[serde_as(as = "serde_with::Bytes")]
338 key: Vec<u8>,
339 #[serde_as(as = "[_; 32]")]
340 hash: [u8; 32],
341}
342
343impl SecretsId {
344 pub fn new(key: Vec<u8>) -> Self {
345 let mut hasher = Blake3::new();
346 hasher.update(&key);
347 let hashed = hasher.finalize();
348 let mut hash = [0; 32];
349 hash.copy_from_slice(&hashed);
350 Self { key, hash }
351 }
352
353 pub fn encode(&self) -> String {
354 bs58::encode(self.hash)
355 .with_alphabet(bs58::Alphabet::BITCOIN)
356 .into_string()
357 }
358
359 pub fn hash(&self) -> &[u8; 32] {
360 &self.hash
361 }
362 pub fn key(&self) -> &[u8] {
363 self.key.as_slice()
364 }
365}
366
367impl Display for SecretsId {
368 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
369 write!(f, "{}", self.encode())
370 }
371}
372
373impl<'a> TryFromFbs<&FbsSecretsId<'a>> for SecretsId {
374 fn try_decode_fbs(key: &FbsSecretsId<'a>) -> Result<Self, WsApiError> {
375 let key_hash = fixed_size_field::<32>("SecretsId.hash", key.hash().bytes())?;
382 Ok(SecretsId {
383 key: key.key().bytes().to_vec(),
384 hash: key_hash,
385 })
386 }
387}
388
389#[non_exhaustive]
403#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
404pub enum MessageOrigin {
405 WebApp(ContractInstanceId),
407 Delegate(DelegateKey),
419}
420
421pub trait DelegateInterface {
466 fn process(
477 ctx: &mut crate::delegate_host::DelegateCtx,
478 parameters: Parameters<'static>,
479 origin: Option<MessageOrigin>,
480 message: InboundDelegateMsg,
481 ) -> Result<Vec<OutboundDelegateMsg>, DelegateError>;
482}
483
484#[serde_as]
485#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
486pub struct DelegateContext(#[serde_as(as = "serde_with::Bytes")] Vec<u8>);
487
488impl DelegateContext {
489 pub const MAX_SIZE: usize = 4096 * 10 * 10;
490
491 pub fn new(bytes: Vec<u8>) -> Self {
492 assert!(bytes.len() < Self::MAX_SIZE);
493 Self(bytes)
494 }
495
496 pub fn append(&mut self, bytes: &mut Vec<u8>) {
497 assert!(self.0.len() + bytes.len() < Self::MAX_SIZE);
498 self.0.append(bytes)
499 }
500
501 pub fn replace(&mut self, bytes: Vec<u8>) {
502 assert!(bytes.len() < Self::MAX_SIZE);
503 let _ = std::mem::replace(&mut self.0, bytes);
504 }
505}
506
507impl AsRef<[u8]> for DelegateContext {
508 fn as_ref(&self) -> &[u8] {
509 &self.0
510 }
511}
512
513#[non_exhaustive]
525#[derive(Serialize, Deserialize, Debug, Clone)]
526pub enum InboundDelegateMsg<'a> {
527 ApplicationMessage(ApplicationMessage),
528 UserResponse(#[serde(borrow)] UserInputResponse<'a>),
529 GetContractResponse(GetContractResponse),
530 PutContractResponse(PutContractResponse),
531 UpdateContractResponse(UpdateContractResponse),
532 SubscribeContractResponse(SubscribeContractResponse),
533 ContractNotification(ContractNotification),
534 DelegateMessage(DelegateMessage),
535}
536
537impl InboundDelegateMsg<'_> {
538 pub fn into_owned(self) -> InboundDelegateMsg<'static> {
539 match self {
540 InboundDelegateMsg::ApplicationMessage(r) => InboundDelegateMsg::ApplicationMessage(r),
541 InboundDelegateMsg::UserResponse(r) => InboundDelegateMsg::UserResponse(r.into_owned()),
542 InboundDelegateMsg::GetContractResponse(r) => {
543 InboundDelegateMsg::GetContractResponse(r)
544 }
545 InboundDelegateMsg::PutContractResponse(r) => {
546 InboundDelegateMsg::PutContractResponse(r)
547 }
548 InboundDelegateMsg::UpdateContractResponse(r) => {
549 InboundDelegateMsg::UpdateContractResponse(r)
550 }
551 InboundDelegateMsg::SubscribeContractResponse(r) => {
552 InboundDelegateMsg::SubscribeContractResponse(r)
553 }
554 InboundDelegateMsg::ContractNotification(r) => {
555 InboundDelegateMsg::ContractNotification(r)
556 }
557 InboundDelegateMsg::DelegateMessage(r) => InboundDelegateMsg::DelegateMessage(r),
558 }
559 }
560
561 pub fn get_context(&self) -> Option<&DelegateContext> {
562 match self {
563 InboundDelegateMsg::ApplicationMessage(ApplicationMessage { context, .. }) => {
564 Some(context)
565 }
566 InboundDelegateMsg::GetContractResponse(GetContractResponse { context, .. }) => {
567 Some(context)
568 }
569 InboundDelegateMsg::PutContractResponse(PutContractResponse { context, .. }) => {
570 Some(context)
571 }
572 InboundDelegateMsg::UpdateContractResponse(UpdateContractResponse {
573 context, ..
574 }) => Some(context),
575 InboundDelegateMsg::SubscribeContractResponse(SubscribeContractResponse {
576 context,
577 ..
578 }) => Some(context),
579 InboundDelegateMsg::ContractNotification(ContractNotification { context, .. }) => {
580 Some(context)
581 }
582 InboundDelegateMsg::DelegateMessage(DelegateMessage { context, .. }) => Some(context),
583 _ => None,
584 }
585 }
586
587 pub fn get_mut_context(&mut self) -> Option<&mut DelegateContext> {
588 match self {
589 InboundDelegateMsg::ApplicationMessage(ApplicationMessage { context, .. }) => {
590 Some(context)
591 }
592 InboundDelegateMsg::GetContractResponse(GetContractResponse { context, .. }) => {
593 Some(context)
594 }
595 InboundDelegateMsg::PutContractResponse(PutContractResponse { context, .. }) => {
596 Some(context)
597 }
598 InboundDelegateMsg::UpdateContractResponse(UpdateContractResponse {
599 context, ..
600 }) => Some(context),
601 InboundDelegateMsg::SubscribeContractResponse(SubscribeContractResponse {
602 context,
603 ..
604 }) => Some(context),
605 InboundDelegateMsg::ContractNotification(ContractNotification { context, .. }) => {
606 Some(context)
607 }
608 InboundDelegateMsg::DelegateMessage(DelegateMessage { context, .. }) => Some(context),
609 _ => None,
610 }
611 }
612}
613
614impl From<ApplicationMessage> for InboundDelegateMsg<'_> {
615 fn from(value: ApplicationMessage) -> Self {
616 Self::ApplicationMessage(value)
617 }
618}
619
620impl<'a> TryFromFbs<&FbsInboundDelegateMsg<'a>> for InboundDelegateMsg<'a> {
621 fn try_decode_fbs(msg: &FbsInboundDelegateMsg<'a>) -> Result<Self, WsApiError> {
622 match msg.inbound_type() {
623 InboundDelegateMsgType::common_ApplicationMessage => {
624 let app_msg = msg.inbound_as_common_application_message().unwrap();
625 let app_msg = ApplicationMessage {
626 payload: app_msg.payload().bytes().to_vec(),
627 context: DelegateContext::new(app_msg.context().bytes().to_vec()),
628 processed: app_msg.processed(),
629 };
630 Ok(InboundDelegateMsg::ApplicationMessage(app_msg))
631 }
632 InboundDelegateMsgType::UserInputResponse => {
633 let user_response = msg.inbound_as_user_input_response().unwrap();
634 let user_response = UserInputResponse {
635 request_id: user_response.request_id(),
636 response: ClientResponse::new(user_response.response().data().bytes().to_vec()),
637 context: DelegateContext::new(
638 user_response.delegate_context().bytes().to_vec(),
639 ),
640 };
641 Ok(InboundDelegateMsg::UserResponse(user_response))
642 }
643 other => Err(unknown_union_discriminant(
647 "InboundDelegateMsgType",
648 other.0,
649 )),
650 }
651 }
652}
653
654#[non_exhaustive]
655#[derive(Serialize, Deserialize, Debug, Clone)]
656pub struct ApplicationMessage {
657 pub payload: Vec<u8>,
658 pub context: DelegateContext,
659 pub processed: bool,
660}
661
662impl ApplicationMessage {
663 pub fn new(payload: Vec<u8>) -> Self {
664 Self {
665 payload,
666 context: DelegateContext::default(),
667 processed: false,
668 }
669 }
670
671 pub fn with_context(mut self, context: DelegateContext) -> Self {
672 self.context = context;
673 self
674 }
675
676 pub fn processed(mut self, p: bool) -> Self {
677 self.processed = p;
678 self
679 }
680}
681
682#[derive(Serialize, Deserialize, Debug, Clone)]
683pub struct UserInputResponse<'a> {
684 pub request_id: u32,
685 #[serde(borrow)]
686 pub response: ClientResponse<'a>,
687 pub context: DelegateContext,
688}
689
690impl UserInputResponse<'_> {
691 pub fn into_owned(self) -> UserInputResponse<'static> {
692 UserInputResponse {
693 request_id: self.request_id,
694 response: self.response.into_owned(),
695 context: self.context,
696 }
697 }
698}
699
700#[derive(Serialize, Deserialize, Debug, Clone)]
701pub enum OutboundDelegateMsg {
702 ApplicationMessage(ApplicationMessage),
704 RequestUserInput(
705 #[serde(deserialize_with = "OutboundDelegateMsg::deser_user_input_req")]
706 UserInputRequest<'static>,
707 ),
708 ContextUpdated(DelegateContext),
710 GetContractRequest(GetContractRequest),
711 PutContractRequest(PutContractRequest),
712 UpdateContractRequest(UpdateContractRequest),
713 SubscribeContractRequest(SubscribeContractRequest),
714 SendDelegateMessage(DelegateMessage),
715}
716
717impl From<ApplicationMessage> for OutboundDelegateMsg {
718 fn from(req: ApplicationMessage) -> Self {
719 Self::ApplicationMessage(req)
720 }
721}
722
723impl From<GetContractRequest> for OutboundDelegateMsg {
724 fn from(req: GetContractRequest) -> Self {
725 Self::GetContractRequest(req)
726 }
727}
728
729impl From<PutContractRequest> for OutboundDelegateMsg {
730 fn from(req: PutContractRequest) -> Self {
731 Self::PutContractRequest(req)
732 }
733}
734
735impl From<UpdateContractRequest> for OutboundDelegateMsg {
736 fn from(req: UpdateContractRequest) -> Self {
737 Self::UpdateContractRequest(req)
738 }
739}
740
741impl From<SubscribeContractRequest> for OutboundDelegateMsg {
742 fn from(req: SubscribeContractRequest) -> Self {
743 Self::SubscribeContractRequest(req)
744 }
745}
746
747impl From<DelegateMessage> for OutboundDelegateMsg {
748 fn from(msg: DelegateMessage) -> Self {
749 Self::SendDelegateMessage(msg)
750 }
751}
752
753impl OutboundDelegateMsg {
754 fn deser_user_input_req<'de, D>(deser: D) -> Result<UserInputRequest<'static>, D::Error>
755 where
756 D: serde::Deserializer<'de>,
757 {
758 let value = <UserInputRequest<'de> as Deserialize>::deserialize(deser)?;
759 Ok(value.into_owned())
760 }
761
762 pub fn processed(&self) -> bool {
763 match self {
764 OutboundDelegateMsg::ApplicationMessage(msg) => msg.processed,
765 OutboundDelegateMsg::GetContractRequest(msg) => msg.processed,
766 OutboundDelegateMsg::PutContractRequest(msg) => msg.processed,
767 OutboundDelegateMsg::UpdateContractRequest(msg) => msg.processed,
768 OutboundDelegateMsg::SubscribeContractRequest(msg) => msg.processed,
769 OutboundDelegateMsg::SendDelegateMessage(msg) => msg.processed,
770 OutboundDelegateMsg::RequestUserInput(_) => true,
771 OutboundDelegateMsg::ContextUpdated(_) => true,
772 }
773 }
774
775 pub fn get_context(&self) -> Option<&DelegateContext> {
776 match self {
777 OutboundDelegateMsg::ApplicationMessage(ApplicationMessage { context, .. }) => {
778 Some(context)
779 }
780 OutboundDelegateMsg::GetContractRequest(GetContractRequest { context, .. }) => {
781 Some(context)
782 }
783 OutboundDelegateMsg::PutContractRequest(PutContractRequest { context, .. }) => {
784 Some(context)
785 }
786 OutboundDelegateMsg::UpdateContractRequest(UpdateContractRequest {
787 context, ..
788 }) => Some(context),
789 OutboundDelegateMsg::SubscribeContractRequest(SubscribeContractRequest {
790 context,
791 ..
792 }) => Some(context),
793 OutboundDelegateMsg::SendDelegateMessage(DelegateMessage { context, .. }) => {
794 Some(context)
795 }
796 _ => None,
797 }
798 }
799
800 pub fn get_mut_context(&mut self) -> Option<&mut DelegateContext> {
801 match self {
802 OutboundDelegateMsg::ApplicationMessage(ApplicationMessage { context, .. }) => {
803 Some(context)
804 }
805 OutboundDelegateMsg::GetContractRequest(GetContractRequest { context, .. }) => {
806 Some(context)
807 }
808 OutboundDelegateMsg::PutContractRequest(PutContractRequest { context, .. }) => {
809 Some(context)
810 }
811 OutboundDelegateMsg::UpdateContractRequest(UpdateContractRequest {
812 context, ..
813 }) => Some(context),
814 OutboundDelegateMsg::SubscribeContractRequest(SubscribeContractRequest {
815 context,
816 ..
817 }) => Some(context),
818 OutboundDelegateMsg::SendDelegateMessage(DelegateMessage { context, .. }) => {
819 Some(context)
820 }
821 _ => None,
822 }
823 }
824}
825
826#[derive(Serialize, Deserialize, Debug, Clone)]
828pub struct GetContractRequest {
829 pub contract_id: ContractInstanceId,
830 pub context: DelegateContext,
831 pub processed: bool,
832}
833
834impl GetContractRequest {
835 pub fn new(contract_id: ContractInstanceId) -> Self {
836 Self {
837 contract_id,
838 context: Default::default(),
839 processed: false,
840 }
841 }
842}
843
844#[derive(Serialize, Deserialize, Debug, Clone)]
846pub struct GetContractResponse {
847 pub contract_id: ContractInstanceId,
848 pub state: Option<WrappedState>,
850 pub context: DelegateContext,
851}
852
853#[derive(Serialize, Deserialize, Debug, Clone)]
855pub struct PutContractRequest {
856 pub contract: ContractContainer,
858 pub state: WrappedState,
860 #[serde(deserialize_with = "RelatedContracts::deser_related_contracts")]
862 pub related_contracts: RelatedContracts<'static>,
863 pub context: DelegateContext,
865 pub processed: bool,
867}
868
869impl PutContractRequest {
870 pub fn new(
871 contract: ContractContainer,
872 state: WrappedState,
873 related_contracts: RelatedContracts<'static>,
874 ) -> Self {
875 Self {
876 contract,
877 state,
878 related_contracts,
879 context: Default::default(),
880 processed: false,
881 }
882 }
883}
884
885#[derive(Serialize, Deserialize, Debug, Clone)]
887pub struct PutContractResponse {
888 pub contract_id: ContractInstanceId,
890 pub result: Result<(), String>,
892 pub context: DelegateContext,
894}
895
896#[derive(Serialize, Deserialize, Debug, Clone)]
898pub struct UpdateContractRequest {
899 pub contract_id: ContractInstanceId,
901 #[serde(deserialize_with = "UpdateContractRequest::deser_update_data")]
903 pub update: UpdateData<'static>,
904 pub context: DelegateContext,
906 pub processed: bool,
908}
909
910impl UpdateContractRequest {
911 pub fn new(contract_id: ContractInstanceId, update: UpdateData<'static>) -> Self {
912 Self {
913 contract_id,
914 update,
915 context: Default::default(),
916 processed: false,
917 }
918 }
919
920 fn deser_update_data<'de, D>(deser: D) -> Result<UpdateData<'static>, D::Error>
921 where
922 D: Deserializer<'de>,
923 {
924 let value = <UpdateData<'de> as Deserialize>::deserialize(deser)?;
925 Ok(value.into_owned())
926 }
927}
928
929#[derive(Serialize, Deserialize, Debug, Clone)]
931pub struct UpdateContractResponse {
932 pub contract_id: ContractInstanceId,
934 pub result: Result<(), String>,
936 pub context: DelegateContext,
938}
939
940#[derive(Serialize, Deserialize, Debug, Clone)]
942pub struct SubscribeContractRequest {
943 pub contract_id: ContractInstanceId,
945 pub context: DelegateContext,
947 pub processed: bool,
949}
950
951impl SubscribeContractRequest {
952 pub fn new(contract_id: ContractInstanceId) -> Self {
953 Self {
954 contract_id,
955 context: Default::default(),
956 processed: false,
957 }
958 }
959}
960
961#[derive(Serialize, Deserialize, Debug, Clone)]
963pub struct SubscribeContractResponse {
964 pub contract_id: ContractInstanceId,
966 pub result: Result<(), String>,
968 pub context: DelegateContext,
970}
971
972#[derive(Serialize, Deserialize, Debug, Clone)]
982pub struct DelegateMessage {
983 pub target: DelegateKey,
985 pub sender: DelegateKey,
987 pub payload: Vec<u8>,
989 pub context: DelegateContext,
991 pub processed: bool,
993}
994
995impl DelegateMessage {
996 pub fn new(target: DelegateKey, sender: DelegateKey, payload: Vec<u8>) -> Self {
997 Self {
998 target,
999 sender,
1000 payload,
1001 context: DelegateContext::default(),
1002 processed: false,
1003 }
1004 }
1005}
1006
1007#[derive(Serialize, Deserialize, Debug, Clone)]
1009pub struct ContractNotification {
1010 pub contract_id: ContractInstanceId,
1012 pub new_state: WrappedState,
1014 pub context: DelegateContext,
1016}
1017
1018#[serde_as]
1019#[derive(Serialize, Deserialize, Debug, Clone)]
1020pub struct NotificationMessage<'a>(
1021 #[serde_as(as = "serde_with::Bytes")]
1022 #[serde(borrow)]
1023 Cow<'a, [u8]>,
1024);
1025
1026impl TryFrom<&serde_json::Value> for NotificationMessage<'static> {
1027 type Error = ();
1028
1029 fn try_from(json: &serde_json::Value) -> Result<NotificationMessage<'static>, ()> {
1030 let bytes = serde_json::to_vec(json).unwrap();
1032 Ok(Self(Cow::Owned(bytes)))
1033 }
1034}
1035
1036impl NotificationMessage<'_> {
1037 pub fn into_owned(self) -> NotificationMessage<'static> {
1038 NotificationMessage(self.0.into_owned().into())
1039 }
1040 pub fn bytes(&self) -> &[u8] {
1041 self.0.as_ref()
1042 }
1043}
1044
1045#[serde_as]
1046#[derive(Serialize, Deserialize, Debug, Clone)]
1047pub struct ClientResponse<'a>(
1048 #[serde_as(as = "serde_with::Bytes")]
1049 #[serde(borrow)]
1050 Cow<'a, [u8]>,
1051);
1052
1053impl Deref for ClientResponse<'_> {
1054 type Target = [u8];
1055
1056 fn deref(&self) -> &Self::Target {
1057 &self.0
1058 }
1059}
1060
1061impl ClientResponse<'_> {
1062 pub fn new(response: Vec<u8>) -> Self {
1063 Self(response.into())
1064 }
1065 pub fn into_owned(self) -> ClientResponse<'static> {
1066 ClientResponse(self.0.into_owned().into())
1067 }
1068 pub fn bytes(&self) -> &[u8] {
1069 self.0.as_ref()
1070 }
1071}
1072
1073#[derive(Serialize, Deserialize, Debug, Clone)]
1074pub struct UserInputRequest<'a> {
1075 pub request_id: u32,
1076 #[serde(borrow)]
1077 pub message: NotificationMessage<'a>,
1079 pub responses: Vec<ClientResponse<'a>>,
1081}
1082
1083impl UserInputRequest<'_> {
1084 pub fn into_owned(self) -> UserInputRequest<'static> {
1085 UserInputRequest {
1086 request_id: self.request_id,
1087 message: self.message.into_owned(),
1088 responses: self.responses.into_iter().map(|r| r.into_owned()).collect(),
1089 }
1090 }
1091}
1092
1093#[doc(hidden)]
1094pub(crate) mod wasm_interface {
1095 use super::*;
1098 use crate::memory::WasmLinearMem;
1099
1100 #[repr(C)]
1101 #[derive(Debug, Clone, Copy)]
1102 pub struct DelegateInterfaceResult {
1103 ptr: i64,
1104 size: u32,
1105 }
1106
1107 impl DelegateInterfaceResult {
1108 pub unsafe fn from_raw(ptr: i64, mem: &WasmLinearMem) -> Self {
1109 let result = Box::leak(Box::from_raw(crate::memory::buf::compute_ptr(
1110 ptr as *mut Self,
1111 mem,
1112 )));
1113 #[cfg(feature = "trace")]
1114 {
1115 tracing::trace!(
1116 "got FFI result @ {ptr} ({:p}) -> {result:?}",
1117 ptr as *mut Self
1118 );
1119 }
1120 *result
1121 }
1122
1123 #[cfg(feature = "contract")]
1124 pub fn into_raw(self) -> i64 {
1125 #[cfg(feature = "trace")]
1126 {
1127 tracing::trace!("returning FFI -> {self:?}");
1128 }
1129 let ptr = Box::into_raw(Box::new(self));
1130 #[cfg(feature = "trace")]
1131 {
1132 tracing::trace!("FFI result ptr: {ptr:p} ({}i64)", ptr as i64);
1133 }
1134 ptr as _
1135 }
1136
1137 pub unsafe fn unwrap(
1138 self,
1139 mem: WasmLinearMem,
1140 ) -> Result<Vec<OutboundDelegateMsg>, DelegateError> {
1141 let ptr = crate::memory::buf::compute_ptr(self.ptr as *mut u8, &mem);
1142 let serialized = std::slice::from_raw_parts(ptr as *const u8, self.size as _);
1143 let value: Result<Vec<OutboundDelegateMsg>, DelegateError> =
1144 bincode::deserialize(serialized)
1145 .map_err(|e| DelegateError::Other(format!("{e}")))?;
1146 #[cfg(feature = "trace")]
1147 {
1148 tracing::trace!(
1149 "got result through FFI; addr: {:p} ({}i64, mapped: {ptr:p})
1150 serialized: {serialized:?}
1151 value: {value:?}",
1152 self.ptr as *mut u8,
1153 self.ptr
1154 );
1155 }
1156 value
1157 }
1158 }
1159
1160 impl From<Result<Vec<OutboundDelegateMsg>, DelegateError>> for DelegateInterfaceResult {
1161 fn from(value: Result<Vec<OutboundDelegateMsg>, DelegateError>) -> Self {
1162 let serialized = bincode::serialize(&value).unwrap();
1163 let size = serialized.len() as _;
1164 let ptr = serialized.as_ptr();
1165 #[cfg(feature = "trace")]
1166 {
1167 tracing::trace!(
1168 "sending result through FFI; addr: {ptr:p} ({}),\n serialized: {serialized:?}\n value: {value:?}",
1169 ptr as i64
1170 );
1171 }
1172 std::mem::forget(serialized);
1173 Self {
1174 ptr: ptr as i64,
1175 size,
1176 }
1177 }
1178 }
1179}
1180
1181#[cfg(test)]
1182mod message_origin_tests {
1183 use super::*;
1184
1185 #[test]
1192 fn webapp_origin_wire_format_is_stable() {
1193 let id = ContractInstanceId::new([0xABu8; 32]);
1194 let origin = MessageOrigin::WebApp(id);
1195 let encoded = bincode::serialize(&origin).unwrap();
1196
1197 let mut expected = vec![0u8, 0, 0, 0];
1200 expected.extend_from_slice(&[0xABu8; 32]);
1201 assert_eq!(encoded, expected);
1202 }
1203
1204 #[test]
1212 fn delegate_origin_wire_format_is_stable() {
1213 let key = DelegateKey::new([0x11u8; 32], crate::code_hash::CodeHash::new([0x22u8; 32]));
1214 let origin = MessageOrigin::Delegate(key);
1215 let encoded = bincode::serialize(&origin).unwrap();
1216
1217 let mut expected = vec![1u8, 0, 0, 0];
1221 expected.extend_from_slice(&[0x11u8; 32]);
1222 expected.extend_from_slice(&[0x22u8; 32]);
1223 assert_eq!(encoded, expected);
1224
1225 let decoded: MessageOrigin = bincode::deserialize(&encoded).unwrap();
1227 assert!(matches!(decoded, MessageOrigin::Delegate(_)));
1228 }
1229
1230 #[test]
1238 fn inbound_delegate_msg_wire_format_is_stable() {
1239 let msg = InboundDelegateMsg::ApplicationMessage(ApplicationMessage::new(vec![0xCC]));
1240 let encoded = bincode::serialize(&msg).unwrap();
1241 assert_eq!(
1242 encoded[..4],
1243 [0, 0, 0, 0],
1244 "ApplicationMessage must stay at variant tag 0 on the wire; \
1245 reordering InboundDelegateMsg variants is a wire-format break"
1246 );
1247 let decoded: InboundDelegateMsg<'_> = bincode::deserialize(&encoded).unwrap();
1249 assert!(matches!(decoded, InboundDelegateMsg::ApplicationMessage(_)));
1250 }
1251}