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