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().iter().as_ref());
283 Ok(DelegateKey {
284 key: key_bytes,
285 code_hash: CodeHash::from_code(key.code_hash().bytes()),
286 })
287 }
288}
289
290#[derive(Debug, thiserror::Error, Serialize, Deserialize)]
292pub enum DelegateError {
293 #[error("de/serialization error: {0}")]
294 Deser(String),
295 #[error("{0}")]
296 Other(String),
297}
298
299fn generate_id<'a>(
300 parameters: &Parameters<'a>,
301 code_data: &DelegateCode<'a>,
302) -> [u8; DELEGATE_HASH_LENGTH] {
303 let contract_hash = code_data.hash();
304
305 let mut hasher = Blake3::new();
306 hasher.update(contract_hash.0.as_slice());
307 hasher.update(parameters.as_ref());
308 let full_key_arr = hasher.finalize();
309
310 debug_assert_eq!(full_key_arr[..].len(), DELEGATE_HASH_LENGTH);
311 let mut key = [0; DELEGATE_HASH_LENGTH];
312 key.copy_from_slice(&full_key_arr);
313 key
314}
315
316#[serde_as]
317#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
318pub struct SecretsId {
319 #[serde_as(as = "serde_with::Bytes")]
320 key: Vec<u8>,
321 #[serde_as(as = "[_; 32]")]
322 hash: [u8; 32],
323}
324
325impl SecretsId {
326 pub fn new(key: Vec<u8>) -> Self {
327 let mut hasher = Blake3::new();
328 hasher.update(&key);
329 let hashed = hasher.finalize();
330 let mut hash = [0; 32];
331 hash.copy_from_slice(&hashed);
332 Self { key, hash }
333 }
334
335 pub fn encode(&self) -> String {
336 bs58::encode(self.hash)
337 .with_alphabet(bs58::Alphabet::BITCOIN)
338 .into_string()
339 }
340
341 pub fn hash(&self) -> &[u8; 32] {
342 &self.hash
343 }
344 pub fn key(&self) -> &[u8] {
345 self.key.as_slice()
346 }
347}
348
349impl Display for SecretsId {
350 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
351 write!(f, "{}", self.encode())
352 }
353}
354
355impl<'a> TryFromFbs<&FbsSecretsId<'a>> for SecretsId {
356 fn try_decode_fbs(key: &FbsSecretsId<'a>) -> Result<Self, WsApiError> {
357 let mut key_hash = [0; 32];
358 key_hash.copy_from_slice(key.hash().bytes().iter().as_ref());
359 Ok(SecretsId {
360 key: key.key().bytes().to_vec(),
361 hash: key_hash,
362 })
363 }
364}
365
366#[non_exhaustive]
380#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
381pub enum MessageOrigin {
382 WebApp(ContractInstanceId),
384 Delegate(DelegateKey),
396}
397
398pub trait DelegateInterface {
443 fn process(
454 ctx: &mut crate::delegate_host::DelegateCtx,
455 parameters: Parameters<'static>,
456 origin: Option<MessageOrigin>,
457 message: InboundDelegateMsg,
458 ) -> Result<Vec<OutboundDelegateMsg>, DelegateError>;
459}
460
461#[serde_as]
462#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
463pub struct DelegateContext(#[serde_as(as = "serde_with::Bytes")] Vec<u8>);
464
465impl DelegateContext {
466 pub const MAX_SIZE: usize = 4096 * 10 * 10;
467
468 pub fn new(bytes: Vec<u8>) -> Self {
469 assert!(bytes.len() < Self::MAX_SIZE);
470 Self(bytes)
471 }
472
473 pub fn append(&mut self, bytes: &mut Vec<u8>) {
474 assert!(self.0.len() + bytes.len() < Self::MAX_SIZE);
475 self.0.append(bytes)
476 }
477
478 pub fn replace(&mut self, bytes: Vec<u8>) {
479 assert!(bytes.len() < Self::MAX_SIZE);
480 let _ = std::mem::replace(&mut self.0, bytes);
481 }
482}
483
484impl AsRef<[u8]> for DelegateContext {
485 fn as_ref(&self) -> &[u8] {
486 &self.0
487 }
488}
489
490#[derive(Serialize, Deserialize, Debug, Clone)]
491pub enum InboundDelegateMsg<'a> {
492 ApplicationMessage(ApplicationMessage),
493 UserResponse(#[serde(borrow)] UserInputResponse<'a>),
494 GetContractResponse(GetContractResponse),
495 PutContractResponse(PutContractResponse),
496 UpdateContractResponse(UpdateContractResponse),
497 SubscribeContractResponse(SubscribeContractResponse),
498 ContractNotification(ContractNotification),
499 DelegateMessage(DelegateMessage),
500}
501
502impl InboundDelegateMsg<'_> {
503 pub fn into_owned(self) -> InboundDelegateMsg<'static> {
504 match self {
505 InboundDelegateMsg::ApplicationMessage(r) => InboundDelegateMsg::ApplicationMessage(r),
506 InboundDelegateMsg::UserResponse(r) => InboundDelegateMsg::UserResponse(r.into_owned()),
507 InboundDelegateMsg::GetContractResponse(r) => {
508 InboundDelegateMsg::GetContractResponse(r)
509 }
510 InboundDelegateMsg::PutContractResponse(r) => {
511 InboundDelegateMsg::PutContractResponse(r)
512 }
513 InboundDelegateMsg::UpdateContractResponse(r) => {
514 InboundDelegateMsg::UpdateContractResponse(r)
515 }
516 InboundDelegateMsg::SubscribeContractResponse(r) => {
517 InboundDelegateMsg::SubscribeContractResponse(r)
518 }
519 InboundDelegateMsg::ContractNotification(r) => {
520 InboundDelegateMsg::ContractNotification(r)
521 }
522 InboundDelegateMsg::DelegateMessage(r) => InboundDelegateMsg::DelegateMessage(r),
523 }
524 }
525
526 pub fn get_context(&self) -> Option<&DelegateContext> {
527 match self {
528 InboundDelegateMsg::ApplicationMessage(ApplicationMessage { context, .. }) => {
529 Some(context)
530 }
531 InboundDelegateMsg::GetContractResponse(GetContractResponse { context, .. }) => {
532 Some(context)
533 }
534 InboundDelegateMsg::PutContractResponse(PutContractResponse { context, .. }) => {
535 Some(context)
536 }
537 InboundDelegateMsg::UpdateContractResponse(UpdateContractResponse {
538 context, ..
539 }) => Some(context),
540 InboundDelegateMsg::SubscribeContractResponse(SubscribeContractResponse {
541 context,
542 ..
543 }) => Some(context),
544 InboundDelegateMsg::ContractNotification(ContractNotification { context, .. }) => {
545 Some(context)
546 }
547 InboundDelegateMsg::DelegateMessage(DelegateMessage { context, .. }) => Some(context),
548 _ => None,
549 }
550 }
551
552 pub fn get_mut_context(&mut self) -> Option<&mut DelegateContext> {
553 match self {
554 InboundDelegateMsg::ApplicationMessage(ApplicationMessage { context, .. }) => {
555 Some(context)
556 }
557 InboundDelegateMsg::GetContractResponse(GetContractResponse { context, .. }) => {
558 Some(context)
559 }
560 InboundDelegateMsg::PutContractResponse(PutContractResponse { context, .. }) => {
561 Some(context)
562 }
563 InboundDelegateMsg::UpdateContractResponse(UpdateContractResponse {
564 context, ..
565 }) => Some(context),
566 InboundDelegateMsg::SubscribeContractResponse(SubscribeContractResponse {
567 context,
568 ..
569 }) => Some(context),
570 InboundDelegateMsg::ContractNotification(ContractNotification { context, .. }) => {
571 Some(context)
572 }
573 InboundDelegateMsg::DelegateMessage(DelegateMessage { context, .. }) => Some(context),
574 _ => None,
575 }
576 }
577}
578
579impl From<ApplicationMessage> for InboundDelegateMsg<'_> {
580 fn from(value: ApplicationMessage) -> Self {
581 Self::ApplicationMessage(value)
582 }
583}
584
585impl<'a> TryFromFbs<&FbsInboundDelegateMsg<'a>> for InboundDelegateMsg<'a> {
586 fn try_decode_fbs(msg: &FbsInboundDelegateMsg<'a>) -> Result<Self, WsApiError> {
587 match msg.inbound_type() {
588 InboundDelegateMsgType::common_ApplicationMessage => {
589 let app_msg = msg.inbound_as_common_application_message().unwrap();
590 let app_msg = ApplicationMessage {
591 payload: app_msg.payload().bytes().to_vec(),
592 context: DelegateContext::new(app_msg.context().bytes().to_vec()),
593 processed: app_msg.processed(),
594 };
595 Ok(InboundDelegateMsg::ApplicationMessage(app_msg))
596 }
597 InboundDelegateMsgType::UserInputResponse => {
598 let user_response = msg.inbound_as_user_input_response().unwrap();
599 let user_response = UserInputResponse {
600 request_id: user_response.request_id(),
601 response: ClientResponse::new(user_response.response().data().bytes().to_vec()),
602 context: DelegateContext::new(
603 user_response.delegate_context().bytes().to_vec(),
604 ),
605 };
606 Ok(InboundDelegateMsg::UserResponse(user_response))
607 }
608 _ => unreachable!("invalid inbound delegate message type"),
609 }
610 }
611}
612
613#[non_exhaustive]
614#[derive(Serialize, Deserialize, Debug, Clone)]
615pub struct ApplicationMessage {
616 pub payload: Vec<u8>,
617 pub context: DelegateContext,
618 pub processed: bool,
619}
620
621impl ApplicationMessage {
622 pub fn new(payload: Vec<u8>) -> Self {
623 Self {
624 payload,
625 context: DelegateContext::default(),
626 processed: false,
627 }
628 }
629
630 pub fn with_context(mut self, context: DelegateContext) -> Self {
631 self.context = context;
632 self
633 }
634
635 pub fn processed(mut self, p: bool) -> Self {
636 self.processed = p;
637 self
638 }
639}
640
641#[derive(Serialize, Deserialize, Debug, Clone)]
642pub struct UserInputResponse<'a> {
643 pub request_id: u32,
644 #[serde(borrow)]
645 pub response: ClientResponse<'a>,
646 pub context: DelegateContext,
647}
648
649impl UserInputResponse<'_> {
650 pub fn into_owned(self) -> UserInputResponse<'static> {
651 UserInputResponse {
652 request_id: self.request_id,
653 response: self.response.into_owned(),
654 context: self.context,
655 }
656 }
657}
658
659#[derive(Serialize, Deserialize, Debug, Clone)]
660pub enum OutboundDelegateMsg {
661 ApplicationMessage(ApplicationMessage),
663 RequestUserInput(
664 #[serde(deserialize_with = "OutboundDelegateMsg::deser_user_input_req")]
665 UserInputRequest<'static>,
666 ),
667 ContextUpdated(DelegateContext),
669 GetContractRequest(GetContractRequest),
670 PutContractRequest(PutContractRequest),
671 UpdateContractRequest(UpdateContractRequest),
672 SubscribeContractRequest(SubscribeContractRequest),
673 SendDelegateMessage(DelegateMessage),
674}
675
676impl From<ApplicationMessage> for OutboundDelegateMsg {
677 fn from(req: ApplicationMessage) -> Self {
678 Self::ApplicationMessage(req)
679 }
680}
681
682impl From<GetContractRequest> for OutboundDelegateMsg {
683 fn from(req: GetContractRequest) -> Self {
684 Self::GetContractRequest(req)
685 }
686}
687
688impl From<PutContractRequest> for OutboundDelegateMsg {
689 fn from(req: PutContractRequest) -> Self {
690 Self::PutContractRequest(req)
691 }
692}
693
694impl From<UpdateContractRequest> for OutboundDelegateMsg {
695 fn from(req: UpdateContractRequest) -> Self {
696 Self::UpdateContractRequest(req)
697 }
698}
699
700impl From<SubscribeContractRequest> for OutboundDelegateMsg {
701 fn from(req: SubscribeContractRequest) -> Self {
702 Self::SubscribeContractRequest(req)
703 }
704}
705
706impl From<DelegateMessage> for OutboundDelegateMsg {
707 fn from(msg: DelegateMessage) -> Self {
708 Self::SendDelegateMessage(msg)
709 }
710}
711
712impl OutboundDelegateMsg {
713 fn deser_user_input_req<'de, D>(deser: D) -> Result<UserInputRequest<'static>, D::Error>
714 where
715 D: serde::Deserializer<'de>,
716 {
717 let value = <UserInputRequest<'de> as Deserialize>::deserialize(deser)?;
718 Ok(value.into_owned())
719 }
720
721 pub fn processed(&self) -> bool {
722 match self {
723 OutboundDelegateMsg::ApplicationMessage(msg) => msg.processed,
724 OutboundDelegateMsg::GetContractRequest(msg) => msg.processed,
725 OutboundDelegateMsg::PutContractRequest(msg) => msg.processed,
726 OutboundDelegateMsg::UpdateContractRequest(msg) => msg.processed,
727 OutboundDelegateMsg::SubscribeContractRequest(msg) => msg.processed,
728 OutboundDelegateMsg::SendDelegateMessage(msg) => msg.processed,
729 OutboundDelegateMsg::RequestUserInput(_) => true,
730 OutboundDelegateMsg::ContextUpdated(_) => true,
731 }
732 }
733
734 pub fn get_context(&self) -> Option<&DelegateContext> {
735 match self {
736 OutboundDelegateMsg::ApplicationMessage(ApplicationMessage { context, .. }) => {
737 Some(context)
738 }
739 OutboundDelegateMsg::GetContractRequest(GetContractRequest { context, .. }) => {
740 Some(context)
741 }
742 OutboundDelegateMsg::PutContractRequest(PutContractRequest { context, .. }) => {
743 Some(context)
744 }
745 OutboundDelegateMsg::UpdateContractRequest(UpdateContractRequest {
746 context, ..
747 }) => Some(context),
748 OutboundDelegateMsg::SubscribeContractRequest(SubscribeContractRequest {
749 context,
750 ..
751 }) => Some(context),
752 OutboundDelegateMsg::SendDelegateMessage(DelegateMessage { context, .. }) => {
753 Some(context)
754 }
755 _ => None,
756 }
757 }
758
759 pub fn get_mut_context(&mut self) -> Option<&mut DelegateContext> {
760 match self {
761 OutboundDelegateMsg::ApplicationMessage(ApplicationMessage { context, .. }) => {
762 Some(context)
763 }
764 OutboundDelegateMsg::GetContractRequest(GetContractRequest { context, .. }) => {
765 Some(context)
766 }
767 OutboundDelegateMsg::PutContractRequest(PutContractRequest { context, .. }) => {
768 Some(context)
769 }
770 OutboundDelegateMsg::UpdateContractRequest(UpdateContractRequest {
771 context, ..
772 }) => Some(context),
773 OutboundDelegateMsg::SubscribeContractRequest(SubscribeContractRequest {
774 context,
775 ..
776 }) => Some(context),
777 OutboundDelegateMsg::SendDelegateMessage(DelegateMessage { context, .. }) => {
778 Some(context)
779 }
780 _ => None,
781 }
782 }
783}
784
785#[derive(Serialize, Deserialize, Debug, Clone)]
787pub struct GetContractRequest {
788 pub contract_id: ContractInstanceId,
789 pub context: DelegateContext,
790 pub processed: bool,
791}
792
793impl GetContractRequest {
794 pub fn new(contract_id: ContractInstanceId) -> Self {
795 Self {
796 contract_id,
797 context: Default::default(),
798 processed: false,
799 }
800 }
801}
802
803#[derive(Serialize, Deserialize, Debug, Clone)]
805pub struct GetContractResponse {
806 pub contract_id: ContractInstanceId,
807 pub state: Option<WrappedState>,
809 pub context: DelegateContext,
810}
811
812#[derive(Serialize, Deserialize, Debug, Clone)]
814pub struct PutContractRequest {
815 pub contract: ContractContainer,
817 pub state: WrappedState,
819 #[serde(deserialize_with = "RelatedContracts::deser_related_contracts")]
821 pub related_contracts: RelatedContracts<'static>,
822 pub context: DelegateContext,
824 pub processed: bool,
826}
827
828impl PutContractRequest {
829 pub fn new(
830 contract: ContractContainer,
831 state: WrappedState,
832 related_contracts: RelatedContracts<'static>,
833 ) -> Self {
834 Self {
835 contract,
836 state,
837 related_contracts,
838 context: Default::default(),
839 processed: false,
840 }
841 }
842}
843
844#[derive(Serialize, Deserialize, Debug, Clone)]
846pub struct PutContractResponse {
847 pub contract_id: ContractInstanceId,
849 pub result: Result<(), String>,
851 pub context: DelegateContext,
853}
854
855#[derive(Serialize, Deserialize, Debug, Clone)]
857pub struct UpdateContractRequest {
858 pub contract_id: ContractInstanceId,
860 #[serde(deserialize_with = "UpdateContractRequest::deser_update_data")]
862 pub update: UpdateData<'static>,
863 pub context: DelegateContext,
865 pub processed: bool,
867}
868
869impl UpdateContractRequest {
870 pub fn new(contract_id: ContractInstanceId, update: UpdateData<'static>) -> Self {
871 Self {
872 contract_id,
873 update,
874 context: Default::default(),
875 processed: false,
876 }
877 }
878
879 fn deser_update_data<'de, D>(deser: D) -> Result<UpdateData<'static>, D::Error>
880 where
881 D: Deserializer<'de>,
882 {
883 let value = <UpdateData<'de> as Deserialize>::deserialize(deser)?;
884 Ok(value.into_owned())
885 }
886}
887
888#[derive(Serialize, Deserialize, Debug, Clone)]
890pub struct UpdateContractResponse {
891 pub contract_id: ContractInstanceId,
893 pub result: Result<(), String>,
895 pub context: DelegateContext,
897}
898
899#[derive(Serialize, Deserialize, Debug, Clone)]
901pub struct SubscribeContractRequest {
902 pub contract_id: ContractInstanceId,
904 pub context: DelegateContext,
906 pub processed: bool,
908}
909
910impl SubscribeContractRequest {
911 pub fn new(contract_id: ContractInstanceId) -> Self {
912 Self {
913 contract_id,
914 context: Default::default(),
915 processed: false,
916 }
917 }
918}
919
920#[derive(Serialize, Deserialize, Debug, Clone)]
922pub struct SubscribeContractResponse {
923 pub contract_id: ContractInstanceId,
925 pub result: Result<(), String>,
927 pub context: DelegateContext,
929}
930
931#[derive(Serialize, Deserialize, Debug, Clone)]
941pub struct DelegateMessage {
942 pub target: DelegateKey,
944 pub sender: DelegateKey,
946 pub payload: Vec<u8>,
948 pub context: DelegateContext,
950 pub processed: bool,
952}
953
954impl DelegateMessage {
955 pub fn new(target: DelegateKey, sender: DelegateKey, payload: Vec<u8>) -> Self {
956 Self {
957 target,
958 sender,
959 payload,
960 context: DelegateContext::default(),
961 processed: false,
962 }
963 }
964}
965
966#[derive(Serialize, Deserialize, Debug, Clone)]
968pub struct ContractNotification {
969 pub contract_id: ContractInstanceId,
971 pub new_state: WrappedState,
973 pub context: DelegateContext,
975}
976
977#[serde_as]
978#[derive(Serialize, Deserialize, Debug, Clone)]
979pub struct NotificationMessage<'a>(
980 #[serde_as(as = "serde_with::Bytes")]
981 #[serde(borrow)]
982 Cow<'a, [u8]>,
983);
984
985impl TryFrom<&serde_json::Value> for NotificationMessage<'static> {
986 type Error = ();
987
988 fn try_from(json: &serde_json::Value) -> Result<NotificationMessage<'static>, ()> {
989 let bytes = serde_json::to_vec(json).unwrap();
991 Ok(Self(Cow::Owned(bytes)))
992 }
993}
994
995impl NotificationMessage<'_> {
996 pub fn into_owned(self) -> NotificationMessage<'static> {
997 NotificationMessage(self.0.into_owned().into())
998 }
999 pub fn bytes(&self) -> &[u8] {
1000 self.0.as_ref()
1001 }
1002}
1003
1004#[serde_as]
1005#[derive(Serialize, Deserialize, Debug, Clone)]
1006pub struct ClientResponse<'a>(
1007 #[serde_as(as = "serde_with::Bytes")]
1008 #[serde(borrow)]
1009 Cow<'a, [u8]>,
1010);
1011
1012impl Deref for ClientResponse<'_> {
1013 type Target = [u8];
1014
1015 fn deref(&self) -> &Self::Target {
1016 &self.0
1017 }
1018}
1019
1020impl ClientResponse<'_> {
1021 pub fn new(response: Vec<u8>) -> Self {
1022 Self(response.into())
1023 }
1024 pub fn into_owned(self) -> ClientResponse<'static> {
1025 ClientResponse(self.0.into_owned().into())
1026 }
1027 pub fn bytes(&self) -> &[u8] {
1028 self.0.as_ref()
1029 }
1030}
1031
1032#[derive(Serialize, Deserialize, Debug, Clone)]
1033pub struct UserInputRequest<'a> {
1034 pub request_id: u32,
1035 #[serde(borrow)]
1036 pub message: NotificationMessage<'a>,
1038 pub responses: Vec<ClientResponse<'a>>,
1040}
1041
1042impl UserInputRequest<'_> {
1043 pub fn into_owned(self) -> UserInputRequest<'static> {
1044 UserInputRequest {
1045 request_id: self.request_id,
1046 message: self.message.into_owned(),
1047 responses: self.responses.into_iter().map(|r| r.into_owned()).collect(),
1048 }
1049 }
1050}
1051
1052#[doc(hidden)]
1053pub(crate) mod wasm_interface {
1054 use super::*;
1057 use crate::memory::WasmLinearMem;
1058
1059 #[repr(C)]
1060 #[derive(Debug, Clone, Copy)]
1061 pub struct DelegateInterfaceResult {
1062 ptr: i64,
1063 size: u32,
1064 }
1065
1066 impl DelegateInterfaceResult {
1067 pub unsafe fn from_raw(ptr: i64, mem: &WasmLinearMem) -> Self {
1068 let result = Box::leak(Box::from_raw(crate::memory::buf::compute_ptr(
1069 ptr as *mut Self,
1070 mem,
1071 )));
1072 #[cfg(feature = "trace")]
1073 {
1074 tracing::trace!(
1075 "got FFI result @ {ptr} ({:p}) -> {result:?}",
1076 ptr as *mut Self
1077 );
1078 }
1079 *result
1080 }
1081
1082 #[cfg(feature = "contract")]
1083 pub fn into_raw(self) -> i64 {
1084 #[cfg(feature = "trace")]
1085 {
1086 tracing::trace!("returning FFI -> {self:?}");
1087 }
1088 let ptr = Box::into_raw(Box::new(self));
1089 #[cfg(feature = "trace")]
1090 {
1091 tracing::trace!("FFI result ptr: {ptr:p} ({}i64)", ptr as i64);
1092 }
1093 ptr as _
1094 }
1095
1096 pub unsafe fn unwrap(
1097 self,
1098 mem: WasmLinearMem,
1099 ) -> Result<Vec<OutboundDelegateMsg>, DelegateError> {
1100 let ptr = crate::memory::buf::compute_ptr(self.ptr as *mut u8, &mem);
1101 let serialized = std::slice::from_raw_parts(ptr as *const u8, self.size as _);
1102 let value: Result<Vec<OutboundDelegateMsg>, DelegateError> =
1103 bincode::deserialize(serialized)
1104 .map_err(|e| DelegateError::Other(format!("{e}")))?;
1105 #[cfg(feature = "trace")]
1106 {
1107 tracing::trace!(
1108 "got result through FFI; addr: {:p} ({}i64, mapped: {ptr:p})
1109 serialized: {serialized:?}
1110 value: {value:?}",
1111 self.ptr as *mut u8,
1112 self.ptr
1113 );
1114 }
1115 value
1116 }
1117 }
1118
1119 impl From<Result<Vec<OutboundDelegateMsg>, DelegateError>> for DelegateInterfaceResult {
1120 fn from(value: Result<Vec<OutboundDelegateMsg>, DelegateError>) -> Self {
1121 let serialized = bincode::serialize(&value).unwrap();
1122 let size = serialized.len() as _;
1123 let ptr = serialized.as_ptr();
1124 #[cfg(feature = "trace")]
1125 {
1126 tracing::trace!(
1127 "sending result through FFI; addr: {ptr:p} ({}),\n serialized: {serialized:?}\n value: {value:?}",
1128 ptr as i64
1129 );
1130 }
1131 std::mem::forget(serialized);
1132 Self {
1133 ptr: ptr as i64,
1134 size,
1135 }
1136 }
1137 }
1138}
1139
1140#[cfg(test)]
1141mod message_origin_tests {
1142 use super::*;
1143
1144 #[test]
1151 fn webapp_origin_wire_format_is_stable() {
1152 let id = ContractInstanceId::new([0xABu8; 32]);
1153 let origin = MessageOrigin::WebApp(id);
1154 let encoded = bincode::serialize(&origin).unwrap();
1155
1156 let mut expected = vec![0u8, 0, 0, 0];
1159 expected.extend_from_slice(&[0xABu8; 32]);
1160 assert_eq!(encoded, expected);
1161 }
1162
1163 #[test]
1171 fn delegate_origin_wire_format_is_stable() {
1172 let key = DelegateKey::new([0x11u8; 32], crate::code_hash::CodeHash::new([0x22u8; 32]));
1173 let origin = MessageOrigin::Delegate(key);
1174 let encoded = bincode::serialize(&origin).unwrap();
1175
1176 let mut expected = vec![1u8, 0, 0, 0];
1180 expected.extend_from_slice(&[0x11u8; 32]);
1181 expected.extend_from_slice(&[0x22u8; 32]);
1182 assert_eq!(encoded, expected);
1183
1184 let decoded: MessageOrigin = bincode::deserialize(&encoded).unwrap();
1186 assert!(matches!(decoded, MessageOrigin::Delegate(_)));
1187 }
1188}