1use std::{
8 borrow::{Borrow, Cow},
9 collections::HashMap,
10 fmt::Display,
11 fs::File,
12 hash::{Hash, Hasher},
13 io::{Cursor, Read},
14 ops::{Deref, DerefMut},
15 path::Path,
16 str::FromStr,
17 sync::Arc,
18};
19
20use blake2::{Blake2s256, Digest};
21use byteorder::LittleEndian;
22use serde::{Deserialize, Deserializer, Serialize, Serializer};
23use serde_with::serde_as;
24
25const CONTRACT_KEY_SIZE: usize = 32;
26
27#[derive(Debug, thiserror::Error, Serialize, Deserialize)]
29pub enum ContractError {
30 #[error("de/serialization error: {0}")]
31 Deser(String),
32 #[error("invalid contract update")]
33 InvalidUpdate,
34 #[error("trying to read an invalid state")]
35 InvalidState,
36 #[error("trying to read an invalid delta")]
37 InvalidDelta,
38 #[error("{0}")]
39 Other(String),
40}
41
42pub trait TryFromTsStd<T>: Sized {
43 fn try_decode(value: T) -> Result<Self, WsApiError>;
44}
45
46#[derive(thiserror::Error, Debug)]
47pub enum WsApiError {
48 #[error("Failed decoding msgpack message from client request: {cause}")]
49 MsgpackDecodeError { cause: String },
50 #[error("Unsupported contract version")]
51 UnsupportedContractVersion,
52 #[error("Failed unpacking contract container")]
53 UnpackingContractContainerError(Box<dyn std::error::Error + Send + Sync + 'static>),
54}
55
56impl WsApiError {
57 pub fn deserialization(cause: String) -> Self {
58 Self::MsgpackDecodeError { cause }
59 }
60}
61
62#[non_exhaustive]
64#[derive(Debug, Serialize, Deserialize)]
65pub struct UpdateModification<'a> {
66 #[serde(borrow)]
67 pub new_state: Option<State<'a>>,
68 pub related: Vec<RelatedContract>,
69}
70
71impl<'a> UpdateModification<'a> {
72 pub fn valid(new_state: State<'a>) -> Self {
74 Self {
75 new_state: Some(new_state),
76 related: vec![],
77 }
78 }
79
80 pub fn requires(related: Vec<RelatedContract>) -> Self {
83 Self {
84 new_state: None,
85 related,
86 }
87 }
88
89 pub fn unwrap_valid(self) -> State<'a> {
93 match self.new_state {
94 Some(s) => s,
95 _ => panic!("failed unwrapping state in modification"),
96 }
97 }
98
99 pub fn get_related(&self) -> &[RelatedContract] {
101 &self.related
102 }
103
104 pub fn into_owned(self) -> UpdateModification<'static> {
106 let Self { new_state, related } = self;
107 UpdateModification {
108 new_state: new_state.map(|s| State::from(s.into_bytes())),
109 related,
110 }
111 }
112}
113
114#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Default)]
118pub struct RelatedContracts<'a> {
119 #[serde(borrow)]
120 map: HashMap<ContractInstanceId, Option<State<'a>>>,
121}
122
123impl RelatedContracts<'_> {
124 pub fn new() -> Self {
125 Self {
126 map: HashMap::new(),
127 }
128 }
129
130 pub fn into_owned(self) -> RelatedContracts<'static> {
132 let mut map = HashMap::with_capacity(self.map.len());
133 for (k, v) in self.map {
134 map.insert(k, v.map(|s| s.into_owned()));
135 }
136 RelatedContracts { map }
137 }
138}
139
140impl<'a> TryFrom<&'a rmpv::Value> for RelatedContracts<'a> {
141 type Error = String;
142
143 fn try_from(value: &'a rmpv::Value) -> Result<Self, Self::Error> {
144 let related_contracts: HashMap<ContractInstanceId, Option<State<'a>>> =
145 HashMap::from_iter(value.as_map().unwrap().iter().map(|(key, val)| {
146 let id = ContractInstanceId::from_bytes(key.as_slice().unwrap()).unwrap();
147 let state = State::from(val.as_slice().unwrap());
148 (id, Some(state))
149 }));
150 Ok(RelatedContracts::from(related_contracts))
151 }
152}
153
154impl<'a> TryFromTsStd<&'a rmpv::Value> for RelatedContracts<'a> {
155 fn try_decode(value: &'a rmpv::Value) -> Result<Self, WsApiError> {
156 let related_contracts: HashMap<ContractInstanceId, Option<State<'a>>> =
157 HashMap::from_iter(value.as_map().unwrap().iter().map(|(key, val)| {
158 let id = ContractInstanceId::from_bytes(key.as_slice().unwrap()).unwrap();
159 let state = State::from(val.as_slice().unwrap());
160 (id, Some(state))
161 }));
162 Ok(RelatedContracts::from(related_contracts))
163 }
164}
165
166impl<'a> From<HashMap<ContractInstanceId, Option<State<'a>>>> for RelatedContracts<'a> {
167 fn from(related_contracts: HashMap<ContractInstanceId, Option<State<'a>>>) -> Self {
168 Self {
169 map: related_contracts,
170 }
171 }
172}
173
174#[derive(Debug, Serialize, Deserialize)]
177pub struct RelatedContract {
178 pub contract_instance_id: ContractInstanceId,
179 pub mode: RelatedMode,
180}
181
182#[derive(Debug, Serialize, Deserialize)]
184pub enum RelatedMode {
185 StateOnce,
187 StateOnceThenDeltas,
189 StateEvery,
191 StateThenStateAndDeltas,
193}
194
195#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
197pub enum ValidateResult {
198 Valid,
199 Invalid,
200 RequestRelated(Vec<ContractInstanceId>),
203}
204
205#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
207pub enum UpdateData<'a> {
208 State(#[serde(borrow)] State<'a>),
209 Delta(#[serde(borrow)] StateDelta<'a>),
210 StateAndDelta {
211 #[serde(borrow)]
212 state: State<'a>,
213 #[serde(borrow)]
214 delta: StateDelta<'a>,
215 },
216 RelatedState {
217 related_to: ContractInstanceId,
218 #[serde(borrow)]
219 state: State<'a>,
220 },
221 RelatedDelta {
222 related_to: ContractInstanceId,
223 #[serde(borrow)]
224 delta: StateDelta<'a>,
225 },
226 RelatedStateAndDelta {
227 related_to: ContractInstanceId,
228 #[serde(borrow)]
229 state: State<'a>,
230 #[serde(borrow)]
231 delta: StateDelta<'a>,
232 },
233}
234
235impl UpdateData<'_> {
236 pub fn size(&self) -> usize {
237 match self {
238 UpdateData::State(state) => state.size(),
239 UpdateData::Delta(delta) => delta.size(),
240 UpdateData::StateAndDelta { state, delta } => state.size() + delta.size(),
241 UpdateData::RelatedState { state, .. } => state.size() + CONTRACT_KEY_SIZE,
242 UpdateData::RelatedDelta { delta, .. } => delta.size() + CONTRACT_KEY_SIZE,
243 UpdateData::RelatedStateAndDelta { state, delta, .. } => {
244 state.size() + delta.size() + CONTRACT_KEY_SIZE
245 }
246 }
247 }
248
249 pub fn unwrap_delta(&self) -> &StateDelta<'_> {
250 match self {
251 UpdateData::Delta(delta) => delta,
252 _ => panic!(),
253 }
254 }
255
256 pub fn into_owned(self) -> UpdateData<'static> {
258 match self {
259 UpdateData::State(s) => UpdateData::State(State::from(s.into_bytes())),
260 UpdateData::Delta(d) => UpdateData::Delta(StateDelta::from(d.into_bytes())),
261 UpdateData::StateAndDelta { state, delta } => UpdateData::StateAndDelta {
262 delta: StateDelta::from(delta.into_bytes()),
263 state: State::from(state.into_bytes()),
264 },
265 UpdateData::RelatedState { related_to, state } => UpdateData::RelatedState {
266 related_to,
267 state: State::from(state.into_bytes()),
268 },
269 UpdateData::RelatedDelta { related_to, delta } => UpdateData::RelatedDelta {
270 related_to,
271 delta: StateDelta::from(delta.into_bytes()),
272 },
273 UpdateData::RelatedStateAndDelta {
274 related_to,
275 state,
276 delta,
277 } => UpdateData::RelatedStateAndDelta {
278 related_to,
279 state: State::from(state.into_bytes()),
280 delta: StateDelta::from(delta.into_bytes()),
281 },
282 }
283 }
284}
285
286impl<'a> From<StateDelta<'a>> for UpdateData<'a> {
287 fn from(delta: StateDelta<'a>) -> Self {
288 UpdateData::Delta(delta)
289 }
290}
291
292impl<'a> TryFromTsStd<&'a rmpv::Value> for UpdateData<'a> {
293 fn try_decode(value: &'a rmpv::Value) -> Result<Self, WsApiError> {
294 let value_map: HashMap<_, _> = HashMap::from_iter(
295 value
296 .as_map()
297 .unwrap()
298 .iter()
299 .map(|(key, val)| (key.as_str().unwrap(), val)),
300 );
301 let mut map_keys = Vec::from_iter(value_map.keys().copied());
302 map_keys.sort();
303 match map_keys.as_slice() {
304 ["delta"] => {
305 let delta = value_map.get("delta").unwrap();
306 Ok(UpdateData::Delta(StateDelta::from(
307 delta.as_slice().unwrap(),
308 )))
309 }
310 ["state"] => {
311 let state = value_map.get("state").unwrap();
312 Ok(UpdateData::Delta(StateDelta::from(
313 state.as_slice().unwrap(),
314 )))
315 }
316 ["delta", "state"] => {
317 let state = value_map.get("state").unwrap();
318 let delta = value_map.get("delta").unwrap();
319 Ok(UpdateData::StateAndDelta {
320 state: State::from(state.as_slice().unwrap()),
321 delta: StateDelta::from(delta.as_slice().unwrap()),
322 })
323 }
324 ["delta", "relatedTo"] => {
325 let delta = value_map.get("delta").unwrap();
326 let related_to = value_map.get("relatedTo").unwrap();
327 Ok(UpdateData::RelatedDelta {
328 delta: StateDelta::from(delta.as_slice().unwrap()),
329 related_to: ContractInstanceId::from_bytes(related_to.as_slice().unwrap())
330 .unwrap(),
331 })
332 }
333 ["state", "relatedTo"] => {
334 let state = value_map.get("state").unwrap();
335 let related_to = value_map.get("relatedTo").unwrap();
336 Ok(UpdateData::RelatedState {
337 state: State::from(state.as_slice().unwrap()),
338 related_to: ContractInstanceId::from_bytes(related_to.as_slice().unwrap())
339 .unwrap(),
340 })
341 }
342 ["delta", "state", "relatedTo"] => {
343 let state = value_map.get("state").unwrap();
344 let delta = value_map.get("delta").unwrap();
345 let related_to = value_map.get("relatedTo").unwrap();
346 Ok(UpdateData::RelatedStateAndDelta {
347 state: State::from(state.as_slice().unwrap()),
348 delta: StateDelta::from(delta.as_slice().unwrap()),
349 related_to: ContractInstanceId::from_bytes(related_to.as_slice().unwrap())
350 .unwrap(),
351 })
352 }
353 _ => unreachable!(),
354 }
355 }
356}
357
358pub trait ContractInterface {
413 fn validate_state(
415 parameters: Parameters<'static>,
416 state: State<'static>,
417 related: RelatedContracts<'static>,
418 ) -> Result<ValidateResult, ContractError>;
419
420 fn validate_delta(
423 parameters: Parameters<'static>,
424 delta: StateDelta<'static>,
425 ) -> Result<bool, ContractError>;
426
427 fn update_state(
429 parameters: Parameters<'static>,
430 state: State<'static>,
431 data: Vec<UpdateData<'static>>,
432 ) -> Result<UpdateModification<'static>, ContractError>;
433
434 fn summarize_state(
437 parameters: Parameters<'static>,
438 state: State<'static>,
439 ) -> Result<StateSummary<'static>, ContractError>;
440
441 fn get_state_delta(
445 parameters: Parameters<'static>,
446 state: State<'static>,
447 summary: StateSummary<'static>,
448 ) -> Result<StateDelta<'static>, ContractError>;
449}
450#[derive(Debug, Serialize, Deserialize, Clone)]
455pub struct Contract<'a> {
456 #[serde(borrow)]
457 pub parameters: Parameters<'a>,
458 #[serde(borrow)]
459 pub data: ContractCode<'a>,
460 key: ContractKey,
461}
462
463impl<'a> Contract<'a> {
464 pub fn new(contract: ContractCode<'a>, parameters: Parameters<'a>) -> Contract<'a> {
466 let key = ContractKey::from((¶meters, &contract));
467 Contract {
468 parameters,
469 data: contract,
470 key,
471 }
472 }
473
474 pub fn key(&self) -> &ContractKey {
476 &self.key
477 }
478
479 pub fn into_code(self) -> ContractCode<'a> {
481 self.data
482 }
483}
484
485impl TryFrom<Vec<u8>> for Contract<'static> {
486 type Error = std::io::Error;
487
488 fn try_from(data: Vec<u8>) -> Result<Self, Self::Error> {
489 use byteorder::ReadBytesExt;
490 let mut reader = Cursor::new(data);
491
492 let params_len = reader.read_u64::<LittleEndian>()?;
493 let mut params_buf = vec![0; params_len as usize];
494 reader.read_exact(&mut params_buf)?;
495 let parameters = Parameters::from(params_buf);
496
497 let contract_len = reader.read_u64::<LittleEndian>()?;
498 let mut contract_buf = vec![0; contract_len as usize];
499 reader.read_exact(&mut contract_buf)?;
500 let contract = ContractCode::from(contract_buf);
501
502 let key = ContractKey::from((¶meters, &contract));
503
504 Ok(Contract {
505 parameters,
506 data: contract,
507 key,
508 })
509 }
510}
511
512impl PartialEq for Contract<'_> {
513 fn eq(&self, other: &Self) -> bool {
514 self.key == other.key
515 }
516}
517
518impl Eq for Contract<'_> {}
519
520impl std::fmt::Display for Contract<'_> {
521 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
522 write!(f, "ContractSpec( key: ")?;
523 internal_fmt_key(&self.key.instance.0, f)?;
524 let data: String = if self.data.data.len() > 8 {
525 self.data.data[..4]
526 .iter()
527 .map(|b| char::from(*b))
528 .chain("...".chars())
529 .chain(self.data.data[4..].iter().map(|b| char::from(*b)))
530 .collect()
531 } else {
532 self.data.data.iter().copied().map(char::from).collect()
533 };
534 write!(f, ", data: [{data}])")
535 }
536}
537
538#[cfg(all(any(test, feature = "testing"), target_family = "unix"))]
539impl<'a> arbitrary::Arbitrary<'a> for Contract<'static> {
540 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
541 let contract: ContractCode = u.arbitrary()?;
542 let parameters: Vec<u8> = u.arbitrary()?;
543 let parameters = Parameters::from(parameters);
544
545 let key = ContractKey::from((¶meters, &contract));
546
547 Ok(Contract {
548 data: contract,
549 parameters,
550 key,
551 })
552 }
553}
554
555#[derive(Debug, Clone, Serialize, Deserialize)]
560#[serde_as]
561#[cfg_attr(feature = "testing", derive(arbitrary::Arbitrary))]
562pub struct Parameters<'a>(
563 #[serde_as(as = "serde_with::Bytes")]
564 #[serde(borrow)]
565 Cow<'a, [u8]>,
566);
567
568impl<'a> Parameters<'a> {
569 pub fn size(&self) -> usize {
571 self.0.len()
572 }
573
574 pub fn into_bytes(self) -> Vec<u8> {
576 self.0.into_owned()
577 }
578
579 pub fn into_owned(self) -> Parameters<'static> {
581 let data: Cow<'static, _> = Cow::from(self.0.into_owned());
582 Parameters(data)
583 }
584}
585
586impl<'a> From<Vec<u8>> for Parameters<'a> {
587 fn from(data: Vec<u8>) -> Self {
588 Parameters(Cow::from(data))
589 }
590}
591
592impl<'a> From<&'a [u8]> for Parameters<'a> {
593 fn from(s: &'a [u8]) -> Self {
594 Parameters(Cow::from(s))
595 }
596}
597
598impl<'a> TryFromTsStd<&'a rmpv::Value> for Parameters<'a> {
599 fn try_decode(value: &'a rmpv::Value) -> Result<Self, WsApiError> {
600 let params = value.as_slice().unwrap();
601 Ok(Parameters::from(params))
602 }
603}
604
605impl<'a> AsRef<[u8]> for Parameters<'a> {
606 fn as_ref(&self) -> &[u8] {
607 match &self.0 {
608 Cow::Borrowed(arr) => arr,
609 Cow::Owned(arr) => arr.as_ref(),
610 }
611 }
612}
613
614#[serde_as]
618#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
619#[cfg_attr(feature = "testing", derive(arbitrary::Arbitrary))]
620pub struct State<'a>(
621 #[serde_as(as = "serde_with::Bytes")]
622 #[serde(borrow)]
623 Cow<'a, [u8]>,
624);
625
626impl State<'_> {
627 pub fn size(&self) -> usize {
629 self.0.len()
630 }
631
632 pub fn into_owned(self) -> State<'static> {
633 State(self.0.into_owned().into())
634 }
635
636 pub fn into_bytes(self) -> Vec<u8> {
638 self.0.into_owned()
639 }
640
641 pub fn to_mut(&mut self) -> &mut Vec<u8> {
643 self.0.to_mut()
644 }
645}
646
647impl<'a> From<Vec<u8>> for State<'a> {
648 fn from(state: Vec<u8>) -> Self {
649 State(Cow::from(state))
650 }
651}
652
653impl<'a> From<&'a [u8]> for State<'a> {
654 fn from(state: &'a [u8]) -> Self {
655 State(Cow::from(state))
656 }
657}
658
659impl<'a> AsRef<[u8]> for State<'a> {
660 fn as_ref(&self) -> &[u8] {
661 match &self.0 {
662 Cow::Borrowed(arr) => arr,
663 Cow::Owned(arr) => arr.as_ref(),
664 }
665 }
666}
667
668impl<'a> Deref for State<'a> {
669 type Target = Cow<'a, [u8]>;
670
671 fn deref(&self) -> &Self::Target {
672 &self.0
673 }
674}
675
676impl<'a> DerefMut for State<'a> {
677 fn deref_mut(&mut self) -> &mut Self::Target {
678 &mut self.0
679 }
680}
681
682impl<'a> std::io::Read for State<'a> {
683 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
684 self.as_ref().read(buf)
685 }
686}
687
688#[serde_as]
695#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
696#[cfg_attr(feature = "testing", derive(arbitrary::Arbitrary))]
697pub struct StateDelta<'a>(
698 #[serde_as(as = "serde_with::Bytes")]
699 #[serde(borrow)]
700 Cow<'a, [u8]>,
701);
702
703impl<'a> StateDelta<'a> {
704 pub fn size(&self) -> usize {
706 self.0.len()
707 }
708
709 pub fn into_bytes(self) -> Vec<u8> {
711 self.0.into_owned()
712 }
713
714 pub fn into_owned(self) -> StateDelta<'static> {
715 StateDelta(self.0.into_owned().into())
716 }
717}
718
719impl<'a> From<Vec<u8>> for StateDelta<'a> {
720 fn from(delta: Vec<u8>) -> Self {
721 StateDelta(Cow::from(delta))
722 }
723}
724
725impl<'a> From<&'a [u8]> for StateDelta<'a> {
726 fn from(delta: &'a [u8]) -> Self {
727 StateDelta(Cow::from(delta))
728 }
729}
730
731impl<'a> AsRef<[u8]> for StateDelta<'a> {
732 fn as_ref(&self) -> &[u8] {
733 match &self.0 {
734 Cow::Borrowed(arr) => arr,
735 Cow::Owned(arr) => arr.as_ref(),
736 }
737 }
738}
739
740impl<'a> Deref for StateDelta<'a> {
741 type Target = Cow<'a, [u8]>;
742
743 fn deref(&self) -> &Self::Target {
744 &self.0
745 }
746}
747
748impl<'a> DerefMut for StateDelta<'a> {
749 fn deref_mut(&mut self) -> &mut Self::Target {
750 &mut self.0
751 }
752}
753
754#[serde_as]
760#[derive(Clone, Serialize, Deserialize, Debug)]
761pub struct StateSummary<'a>(
762 #[serde_as(as = "serde_with::Bytes")]
763 #[serde(borrow)]
764 Cow<'a, [u8]>,
765);
766
767impl StateSummary<'_> {
768 pub fn into_bytes(self) -> Vec<u8> {
770 self.0.into_owned()
771 }
772
773 pub fn size(&self) -> usize {
775 self.0.len()
776 }
777
778 pub fn into_owned(self) -> StateSummary<'static> {
779 StateSummary(self.0.into_owned().into())
780 }
781}
782
783impl<'a> From<Vec<u8>> for StateSummary<'a> {
784 fn from(state: Vec<u8>) -> Self {
785 StateSummary(Cow::from(state))
786 }
787}
788
789impl<'a> From<&'a [u8]> for StateSummary<'a> {
790 fn from(state: &'a [u8]) -> Self {
791 StateSummary(Cow::from(state))
792 }
793}
794
795impl<'a> AsRef<[u8]> for StateSummary<'a> {
796 fn as_ref(&self) -> &[u8] {
797 match &self.0 {
798 Cow::Borrowed(arr) => arr,
799 Cow::Owned(arr) => arr.as_ref(),
800 }
801 }
802}
803
804impl<'a> Deref for StateSummary<'a> {
805 type Target = Cow<'a, [u8]>;
806
807 fn deref(&self) -> &Self::Target {
808 &self.0
809 }
810}
811
812impl<'a> DerefMut for StateSummary<'a> {
813 fn deref_mut(&mut self) -> &mut Self::Target {
814 &mut self.0
815 }
816}
817
818#[cfg(all(any(test, feature = "testing"), target_family = "unix"))]
819impl<'a> arbitrary::Arbitrary<'a> for StateSummary<'static> {
820 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
821 let data: Vec<u8> = u.arbitrary()?;
822 Ok(StateSummary::from(data))
823 }
824}
825
826#[serde_as]
831#[derive(Debug, Serialize, Deserialize, Clone)]
832pub struct ContractCode<'a> {
833 #[serde_as(as = "serde_with::Bytes")]
834 #[serde(borrow)]
835 data: Cow<'a, [u8]>,
836 #[serde_as(as = "[_; CONTRACT_KEY_SIZE]")]
837 key: [u8; CONTRACT_KEY_SIZE],
838}
839
840impl ContractCode<'_> {
841 pub fn hash(&self) -> &[u8; CONTRACT_KEY_SIZE] {
843 &self.key
844 }
845
846 pub fn hash_str(&self) -> String {
848 Self::encode_hash(&self.key)
849 }
850
851 pub fn data(&self) -> &[u8] {
853 &self.data
854 }
855
856 pub fn into_bytes(self) -> Vec<u8> {
858 self.data.to_vec()
859 }
860
861 pub fn encode_hash(hash: &[u8; CONTRACT_KEY_SIZE]) -> String {
863 bs58::encode(hash)
864 .with_alphabet(bs58::Alphabet::BITCOIN)
865 .into_string()
866 }
867
868 pub fn into_owned(self) -> ContractCode<'static> {
870 ContractCode {
871 data: self.data.into_owned().into(),
872 key: self.key,
873 }
874 }
875
876 fn gen_key(data: &[u8]) -> [u8; CONTRACT_KEY_SIZE] {
877 let mut hasher = Blake2s256::new();
878 hasher.update(data);
879 let key_arr = hasher.finalize();
880 debug_assert_eq!(key_arr[..].len(), CONTRACT_KEY_SIZE);
881 let mut key = [0; CONTRACT_KEY_SIZE];
882 key.copy_from_slice(&key_arr);
883 key
884 }
885}
886
887impl From<Vec<u8>> for ContractCode<'static> {
888 fn from(data: Vec<u8>) -> Self {
889 let key = ContractCode::gen_key(&data);
890 ContractCode {
891 data: Cow::from(data),
892 key,
893 }
894 }
895}
896
897impl<'a> From<&'a [u8]> for ContractCode<'a> {
898 fn from(data: &'a [u8]) -> ContractCode {
899 let key = ContractCode::gen_key(data);
900 ContractCode {
901 data: Cow::from(data),
902 key,
903 }
904 }
905}
906
907impl<'a> TryFromTsStd<&'a rmpv::Value> for ContractCode<'a> {
908 fn try_decode(value: &'a rmpv::Value) -> Result<Self, WsApiError> {
909 let data = value.as_slice().unwrap();
910 Ok(ContractCode::from(data))
911 }
912}
913
914impl PartialEq for ContractCode<'_> {
915 fn eq(&self, other: &Self) -> bool {
916 self.key == other.key
917 }
918}
919
920impl Eq for ContractCode<'_> {}
921
922#[cfg(all(any(test, feature = "testing"), target_family = "unix"))]
923impl<'a> arbitrary::Arbitrary<'a> for ContractCode<'static> {
924 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
925 let data: Vec<u8> = u.arbitrary()?;
926 Ok(ContractCode::from(data))
927 }
928}
929
930impl std::fmt::Display for ContractCode<'_> {
931 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
932 write!(f, "Contract( key: ")?;
933 internal_fmt_key(&self.key, f)?;
934 let data: String = if self.data.len() > 8 {
935 self.data[..4]
936 .iter()
937 .map(|b| char::from(*b))
938 .chain("...".chars())
939 .chain(self.data[4..].iter().map(|b| char::from(*b)))
940 .collect()
941 } else {
942 self.data.iter().copied().map(char::from).collect()
943 };
944 write!(f, ", data: [{data}])")
945 }
946}
947
948#[serde_as]
950#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize, Hash)]
951#[cfg_attr(
952 all(any(test, feature = "testing"), target_family = "unix"),
953 derive(arbitrary::Arbitrary)
954)]
955#[repr(transparent)]
956pub struct ContractInstanceId(#[serde_as(as = "[_; CONTRACT_KEY_SIZE]")] [u8; CONTRACT_KEY_SIZE]);
957
958impl ContractInstanceId {
959 pub fn encode(&self) -> String {
961 bs58::encode(self.0)
962 .with_alphabet(bs58::Alphabet::BITCOIN)
963 .into_string()
964 }
965
966 fn from_bytes(bytes: impl AsRef<[u8]>) -> Result<Self, bs58::decode::Error> {
968 let mut spec = [0; CONTRACT_KEY_SIZE];
969 bs58::decode(bytes)
970 .with_alphabet(bs58::Alphabet::BITCOIN)
971 .into(&mut spec)?;
972 Ok(Self(spec))
973 }
974}
975
976impl FromStr for ContractInstanceId {
977 type Err = bs58::decode::Error;
978
979 fn from_str(s: &str) -> Result<Self, Self::Err> {
980 ContractInstanceId::from_bytes(s)
981 }
982}
983
984impl TryFrom<String> for ContractInstanceId {
985 type Error = bs58::decode::Error;
986
987 fn try_from(s: String) -> Result<Self, Self::Error> {
988 ContractInstanceId::from_bytes(s)
989 }
990}
991
992impl<'a, T, U> From<(T, U)> for ContractInstanceId
993where
994 T: Borrow<Parameters<'a>>,
995 U: Borrow<ContractCode<'a>>,
996{
997 fn from(val: (T, U)) -> Self {
998 let (parameters, code_data) = (val.0.borrow(), val.1.borrow());
999 generate_id(parameters, code_data)
1000 }
1001}
1002
1003impl Display for ContractInstanceId {
1004 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1005 write!(f, "{}", self.encode())
1006 }
1007}
1008
1009#[serde_as]
1011#[derive(Debug, Eq, Clone, Serialize, Deserialize)]
1012#[cfg_attr(
1013 all(any(test, feature = "testing"), target_family = "unix"),
1014 derive(arbitrary::Arbitrary)
1015)]
1016pub struct ContractKey {
1017 instance: ContractInstanceId,
1018 #[serde_as(as = "Option<[_; CONTRACT_KEY_SIZE]>")]
1019 code: Option<[u8; CONTRACT_KEY_SIZE]>,
1020}
1021
1022impl PartialEq for ContractKey {
1023 fn eq(&self, other: &Self) -> bool {
1024 self.instance == other.instance
1025 }
1026}
1027
1028impl std::hash::Hash for ContractKey {
1029 fn hash<H: Hasher>(&self, state: &mut H) {
1030 self.instance.0.hash(state);
1031 }
1032}
1033
1034impl From<ContractInstanceId> for ContractKey {
1035 fn from(instance: ContractInstanceId) -> Self {
1036 Self {
1037 instance,
1038 code: None,
1039 }
1040 }
1041}
1042
1043impl<'a, T, U> From<(T, U)> for ContractKey
1044where
1045 T: Borrow<Parameters<'a>>,
1046 U: Borrow<ContractCode<'a>>,
1047{
1048 fn from(val: (T, U)) -> Self {
1049 let (parameters, code_data) = (val.0.borrow(), val.1.borrow());
1050 let id = generate_id(parameters, code_data);
1051 let contract_hash = code_data.hash();
1052 Self {
1053 instance: id,
1054 code: Some(*contract_hash),
1055 }
1056 }
1057}
1058
1059impl ContractKey {
1060 pub fn from_id(instance: impl Into<String>) -> Result<Self, bs58::decode::Error> {
1062 let instance = ContractInstanceId::try_from(instance.into())?;
1063 Ok(Self {
1064 instance,
1065 code: None,
1066 })
1067 }
1068
1069 pub fn bytes(&self) -> &[u8] {
1071 self.instance.0.as_ref()
1072 }
1073
1074 pub fn code_hash(&self) -> Option<&[u8; CONTRACT_KEY_SIZE]> {
1076 self.code.as_ref()
1077 }
1078
1079 pub fn encoded_code_hash(&self) -> Option<String> {
1081 self.code.as_ref().map(|c| {
1082 bs58::encode(c)
1083 .with_alphabet(bs58::Alphabet::BITCOIN)
1084 .into_string()
1085 })
1086 }
1087
1088 pub fn decode(
1091 contract_key: impl Into<String>,
1092 parameters: Parameters,
1093 ) -> Result<Self, bs58::decode::Error> {
1094 let mut contract = [0; CONTRACT_KEY_SIZE];
1095 bs58::decode(contract_key.into())
1096 .with_alphabet(bs58::Alphabet::BITCOIN)
1097 .into(&mut contract)?;
1098
1099 let mut hasher = Blake2s256::new();
1100 hasher.update(contract);
1101 hasher.update(parameters.as_ref());
1102 let full_key_arr = hasher.finalize();
1103
1104 let mut spec = [0; CONTRACT_KEY_SIZE];
1105 spec.copy_from_slice(&full_key_arr);
1106 Ok(Self {
1107 instance: ContractInstanceId(spec),
1108 code: Some(contract),
1109 })
1110 }
1111
1112 pub fn encoded_contract_id(&self) -> String {
1114 self.instance.encode()
1115 }
1116}
1117
1118impl Deref for ContractKey {
1119 type Target = [u8];
1120
1121 fn deref(&self) -> &Self::Target {
1122 &self.instance.0
1123 }
1124}
1125
1126impl std::fmt::Display for ContractKey {
1127 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1128 self.instance.fmt(f)
1129 }
1130}
1131
1132impl TryFromTsStd<&rmpv::Value> for ContractKey {
1133 fn try_decode(value: &rmpv::Value) -> Result<Self, WsApiError> {
1134 let key_map: HashMap<&str, &rmpv::Value> = match value.as_map() {
1135 Some(map_value) => HashMap::from_iter(
1136 map_value
1137 .iter()
1138 .map(|(key, val)| (key.as_str().unwrap(), val)),
1139 ),
1140 _ => {
1141 return Err(WsApiError::MsgpackDecodeError {
1142 cause: "Failed decoding ContractKey, input value is not a map".to_string(),
1143 })
1144 }
1145 };
1146
1147 let instance_id = match key_map.get("instance") {
1148 Some(instance_value) => bs58::encode(&instance_value.as_slice().unwrap()).into_string(),
1149 _ => {
1150 return Err(WsApiError::MsgpackDecodeError {
1151 cause: "Failed decoding WrappedContract, instance not found".to_string(),
1152 })
1153 }
1154 };
1155
1156 Ok(ContractKey::from_id(instance_id).unwrap())
1157 }
1158}
1159
1160fn generate_id<'a>(
1161 parameters: &Parameters<'a>,
1162 code_data: &ContractCode<'a>,
1163) -> ContractInstanceId {
1164 let contract_hash = code_data.hash();
1165
1166 let mut hasher = Blake2s256::new();
1167 hasher.update(contract_hash);
1168 hasher.update(parameters.as_ref());
1169 let full_key_arr = hasher.finalize();
1170
1171 debug_assert_eq!(full_key_arr[..].len(), CONTRACT_KEY_SIZE);
1172 let mut spec = [0; CONTRACT_KEY_SIZE];
1173 spec.copy_from_slice(&full_key_arr);
1174 ContractInstanceId(spec)
1175}
1176
1177#[inline]
1178fn internal_fmt_key(
1179 key: &[u8; CONTRACT_KEY_SIZE],
1180 f: &mut std::fmt::Formatter<'_>,
1181) -> std::fmt::Result {
1182 let r = bs58::encode(key)
1183 .with_alphabet(bs58::Alphabet::BITCOIN)
1184 .into_string();
1185 write!(f, "{}", &r[..8])
1186}
1187
1188#[derive(Debug, PartialEq, Eq, Clone, serde::Serialize, serde::Deserialize)]
1190#[cfg_attr(feature = "testing", derive(arbitrary::Arbitrary))]
1191pub struct WrappedState(
1192 #[serde(
1193 serialize_with = "WrappedState::ser_state",
1194 deserialize_with = "WrappedState::deser_state"
1195 )]
1196 Arc<Vec<u8>>,
1197);
1198
1199impl WrappedState {
1200 pub fn new(bytes: Vec<u8>) -> Self {
1201 WrappedState(Arc::new(bytes))
1202 }
1203
1204 pub fn size(&self) -> usize {
1205 self.0.len()
1206 }
1207
1208 fn ser_state<S>(data: &Arc<Vec<u8>>, ser: S) -> Result<S::Ok, S::Error>
1209 where
1210 S: Serializer,
1211 {
1212 serde_bytes::serialize(&**data, ser)
1213 }
1214
1215 fn deser_state<'de, D>(deser: D) -> Result<Arc<Vec<u8>>, D::Error>
1216 where
1217 D: Deserializer<'de>,
1218 {
1219 let data: Vec<u8> = serde_bytes::deserialize(deser)?;
1220 Ok(Arc::new(data))
1221 }
1222}
1223
1224impl From<Vec<u8>> for WrappedState {
1225 fn from(bytes: Vec<u8>) -> Self {
1226 Self::new(bytes)
1227 }
1228}
1229
1230impl TryFromTsStd<&rmpv::Value> for WrappedState {
1231 fn try_decode(value: &rmpv::Value) -> Result<Self, WsApiError> {
1232 let state = value.as_slice().unwrap().to_vec();
1233 Ok(WrappedState::from(state))
1234 }
1235}
1236
1237impl AsRef<[u8]> for WrappedState {
1238 fn as_ref(&self) -> &[u8] {
1239 self.0.as_ref()
1240 }
1241}
1242
1243impl Deref for WrappedState {
1244 type Target = [u8];
1245
1246 fn deref(&self) -> &Self::Target {
1247 &self.0
1248 }
1249}
1250
1251impl Borrow<[u8]> for WrappedState {
1252 fn borrow(&self) -> &[u8] {
1253 &self.0
1254 }
1255}
1256
1257impl std::fmt::Display for WrappedState {
1258 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1259 let data: String = if self.0.len() > 8 {
1260 let last_4 = self.0.len() - 4;
1261 self.0[..4]
1262 .iter()
1263 .map(|b| char::from(*b))
1264 .chain("...".chars())
1265 .chain(self.0[last_4..].iter().map(|b| char::from(*b)))
1266 .collect()
1267 } else {
1268 self.0.iter().copied().map(char::from).collect()
1269 };
1270 write!(f, "ContractState(data: [{data}])")
1271 }
1272}
1273
1274#[non_exhaustive]
1276#[derive(Clone, Debug, Serialize, Deserialize)]
1277pub struct WrappedContract {
1278 #[serde(
1279 serialize_with = "WrappedContract::ser_contract_data",
1280 deserialize_with = "WrappedContract::deser_contract_data"
1281 )]
1282 pub data: Arc<ContractCode<'static>>,
1283 #[serde(
1284 serialize_with = "WrappedContract::ser_params",
1285 deserialize_with = "WrappedContract::deser_params"
1286 )]
1287 pub params: Parameters<'static>,
1288 pub key: ContractKey,
1289}
1290
1291impl PartialEq for WrappedContract {
1292 fn eq(&self, other: &Self) -> bool {
1293 self.key == other.key
1294 }
1295}
1296
1297impl Eq for WrappedContract {}
1298
1299impl WrappedContract {
1300 pub fn new(data: Arc<ContractCode<'static>>, params: Parameters<'static>) -> WrappedContract {
1301 let key = ContractKey::from((¶ms, &*data));
1302 WrappedContract { data, params, key }
1303 }
1304
1305 #[inline]
1306 pub fn key(&self) -> &ContractKey {
1307 &self.key
1308 }
1309
1310 #[inline]
1311 pub fn code(&self) -> &Arc<ContractCode<'static>> {
1312 &self.data
1313 }
1314
1315 #[inline]
1316 pub fn params(&self) -> &Parameters<'static> {
1317 &self.params
1318 }
1319
1320 pub fn get_data_from_fs(path: &Path) -> Result<ContractCode<'static>, std::io::Error> {
1321 let mut contract_file = File::open(path)?;
1322 let mut contract_data = if let Ok(md) = contract_file.metadata() {
1323 Vec::with_capacity(md.len() as usize)
1324 } else {
1325 Vec::new()
1326 };
1327 contract_file.read_to_end(&mut contract_data)?;
1328 Ok(ContractCode::from(contract_data))
1329 }
1330
1331 fn ser_contract_data<S>(data: &Arc<ContractCode<'_>>, ser: S) -> Result<S::Ok, S::Error>
1332 where
1333 S: Serializer,
1334 {
1335 data.serialize(ser)
1336 }
1337
1338 fn deser_contract_data<'de, D>(_deser: D) -> Result<Arc<ContractCode<'static>>, D::Error>
1339 where
1340 D: Deserializer<'de>,
1341 {
1342 todo!()
1345 }
1346
1347 fn ser_params<S>(data: &Parameters<'_>, ser: S) -> Result<S::Ok, S::Error>
1348 where
1349 S: Serializer,
1350 {
1351 data.serialize(ser)
1352 }
1353
1354 fn deser_params<'de, D>(_deser: D) -> Result<Parameters<'static>, D::Error>
1355 where
1356 D: Deserializer<'de>,
1357 {
1358 todo!()
1361 }
1362}
1363
1364impl<'a> TryFrom<(&'a Path, Parameters<'static>)> for WrappedContract {
1365 type Error = std::io::Error;
1366 fn try_from(data: (&'a Path, Parameters<'static>)) -> Result<Self, Self::Error> {
1367 let (path, params) = data;
1368 let data = Arc::new(Self::get_data_from_fs(path)?);
1369 Ok(WrappedContract::new(data, params))
1370 }
1371}
1372
1373impl TryFromTsStd<&rmpv::Value> for WrappedContract {
1374 fn try_decode(value: &rmpv::Value) -> Result<Self, WsApiError> {
1375 let contract_map: HashMap<&str, &rmpv::Value> = match value.as_map() {
1376 Some(map_value) => HashMap::from_iter(
1377 map_value
1378 .iter()
1379 .map(|(key, val)| (key.as_str().unwrap(), val)),
1380 ),
1381 _ => {
1382 return Err(WsApiError::MsgpackDecodeError {
1383 cause: "Failed decoding WrappedContract, input value is not a map".to_string(),
1384 })
1385 }
1386 };
1387
1388 let key = match contract_map.get("key") {
1389 Some(key_value) => ContractKey::try_decode(*key_value).unwrap(),
1390 _ => {
1391 return Err(WsApiError::MsgpackDecodeError {
1392 cause: "Failed decoding WrappedContract, key not found".to_string(),
1393 })
1394 }
1395 };
1396
1397 let data = match contract_map.get("data") {
1398 Some(contract_data_value) => Arc::new(
1399 ContractCode::try_decode(*contract_data_value)
1400 .unwrap()
1401 .into_owned(),
1402 ),
1403 _ => {
1404 return Err(WsApiError::MsgpackDecodeError {
1405 cause: "Failed decoding WrappedContract, data not found".to_string(),
1406 })
1407 }
1408 };
1409
1410 let params = match contract_map.get("parameters") {
1411 Some(params_value) => Parameters::try_decode(*params_value).unwrap().into_owned(),
1412 _ => {
1413 return Err(WsApiError::MsgpackDecodeError {
1414 cause: "Failed decoding WrappedContract, parameters not found".to_string(),
1415 })
1416 }
1417 };
1418
1419 Ok(Self { data, params, key })
1420 }
1421}
1422
1423impl TryInto<Vec<u8>> for WrappedContract {
1424 type Error = ();
1425 fn try_into(self) -> Result<Vec<u8>, Self::Error> {
1426 Arc::try_unwrap(self.data)
1427 .map(|r| r.into_bytes())
1428 .map_err(|_| ())
1429 }
1430}
1431
1432impl Display for WrappedContract {
1433 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1434 write!(f, "Contract(")?;
1435 self.key.fmt(f)?;
1436 write!(f, ")")
1437 }
1438}
1439
1440#[cfg(feature = "testing")]
1441impl<'a> arbitrary::Arbitrary<'a> for WrappedContract {
1442 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
1443 use arbitrary::Arbitrary;
1444 let data: ContractCode = Arbitrary::arbitrary(u)?;
1445 let param_bytes: Vec<u8> = Arbitrary::arbitrary(u)?;
1446 let params = Parameters::from(param_bytes);
1447 let key = ContractKey::from((¶ms, &data));
1448 Ok(Self {
1449 data: Arc::new(data),
1450 params,
1451 key,
1452 })
1453 }
1454}
1455
1456#[doc(hidden)]
1457pub(crate) mod wasm_interface {
1458 use super::*;
1461 use crate::WasmLinearMem;
1462
1463 #[repr(i32)]
1464 enum ResultKind {
1465 ValidateState = 0,
1466 ValidateDelta = 1,
1467 UpdateState = 2,
1468 SummarizeState = 3,
1469 StateDelta = 4,
1470 }
1471
1472 impl From<i32> for ResultKind {
1473 fn from(v: i32) -> Self {
1474 match v {
1475 0 => ResultKind::ValidateState,
1476 1 => ResultKind::ValidateDelta,
1477 2 => ResultKind::UpdateState,
1478 3 => ResultKind::SummarizeState,
1479 4 => ResultKind::StateDelta,
1480 _ => panic!(),
1481 }
1482 }
1483 }
1484
1485 #[doc(hidden)]
1486 #[repr(C)]
1487 #[derive(Debug, Clone, Copy)]
1488 pub struct ContractInterfaceResult {
1489 ptr: i64,
1490 kind: i32,
1491 size: u32,
1492 }
1493
1494 impl ContractInterfaceResult {
1495 pub unsafe fn unwrap_validate_state_res(
1496 self,
1497 mem: WasmLinearMem,
1498 ) -> Result<ValidateResult, ContractError> {
1499 #![allow(clippy::let_and_return)]
1500 let kind = ResultKind::from(self.kind);
1501 match kind {
1502 ResultKind::ValidateState => {
1503 let ptr = crate::buf::compute_ptr(self.ptr as *mut u8, &mem);
1504 let serialized = std::slice::from_raw_parts(ptr as *const u8, self.size as _);
1505 let value = bincode::deserialize(serialized)
1506 .map_err(|e| ContractError::Other(format!("{e}")))?;
1507 #[cfg(feature = "trace")]
1508 self.log_input(serialized, &value, ptr);
1509 value
1510 }
1511 _ => unreachable!(),
1512 }
1513 }
1514
1515 pub unsafe fn unwrap_validate_delta_res(
1516 self,
1517 mem: WasmLinearMem,
1518 ) -> Result<bool, ContractError> {
1519 #![allow(clippy::let_and_return)]
1520 let kind = ResultKind::from(self.kind);
1521 match kind {
1522 ResultKind::ValidateDelta => {
1523 let ptr = crate::buf::compute_ptr(self.ptr as *mut u8, &mem);
1524 let serialized = std::slice::from_raw_parts(ptr as *const u8, self.size as _);
1525 let value = bincode::deserialize(serialized)
1526 .map_err(|e| ContractError::Other(format!("{e}")))?;
1527 #[cfg(feature = "trace")]
1528 self.log_input(serialized, &value, ptr);
1529 value
1530 }
1531 _ => unreachable!(),
1532 }
1533 }
1534
1535 pub unsafe fn unwrap_update_state(
1536 self,
1537 mem: WasmLinearMem,
1538 ) -> Result<UpdateModification<'static>, ContractError> {
1539 let kind = ResultKind::from(self.kind);
1540 match kind {
1541 ResultKind::UpdateState => {
1542 let ptr = crate::buf::compute_ptr(self.ptr as *mut u8, &mem);
1543 let serialized = std::slice::from_raw_parts(ptr as *const u8, self.size as _);
1544 let value: Result<UpdateModification<'_>, ContractError> =
1545 bincode::deserialize(serialized)
1546 .map_err(|e| ContractError::Other(format!("{e}")))?;
1547 #[cfg(feature = "trace")]
1548 self.log_input(serialized, &value, ptr);
1549 value.map(|r| r.into_owned())
1552 }
1553 _ => unreachable!(),
1554 }
1555 }
1556
1557 pub unsafe fn unwrap_summarize_state(
1558 self,
1559 mem: WasmLinearMem,
1560 ) -> Result<StateSummary<'static>, ContractError> {
1561 let kind = ResultKind::from(self.kind);
1562 match kind {
1563 ResultKind::SummarizeState => {
1564 let ptr = crate::buf::compute_ptr(self.ptr as *mut u8, &mem);
1565 let serialized = std::slice::from_raw_parts(ptr as *const u8, self.size as _);
1566 let value: Result<StateSummary<'static>, ContractError> =
1567 bincode::deserialize(serialized)
1568 .map_err(|e| ContractError::Other(format!("{e}")))?;
1569 #[cfg(feature = "trace")]
1570 self.log_input(serialized, &value, ptr);
1571 value.map(|s| StateSummary::from(s.into_bytes()))
1574 }
1575 _ => unreachable!(),
1576 }
1577 }
1578
1579 pub unsafe fn unwrap_get_state_delta(
1580 self,
1581 mem: WasmLinearMem,
1582 ) -> Result<StateDelta<'static>, ContractError> {
1583 let kind = ResultKind::from(self.kind);
1584 match kind {
1585 ResultKind::StateDelta => {
1586 let ptr = crate::buf::compute_ptr(self.ptr as *mut u8, &mem);
1587 let serialized = std::slice::from_raw_parts(ptr as *const u8, self.size as _);
1588 let value: Result<StateDelta<'static>, ContractError> =
1589 bincode::deserialize(serialized)
1590 .map_err(|e| ContractError::Other(format!("{e}")))?;
1591 #[cfg(feature = "trace")]
1592 self.log_input(serialized, &value, ptr);
1593 value.map(|d| StateDelta::from(d.into_bytes()))
1596 }
1597 _ => unreachable!(),
1598 }
1599 }
1600
1601 pub fn into_raw(self) -> i64 {
1602 #[cfg(feature = "trace")]
1603 {
1604 tracing::trace!("returning FFI -> {self:?}");
1605 }
1606 let ptr = Box::into_raw(Box::new(self));
1607 #[cfg(feature = "trace")]
1608 {
1609 tracing::trace!("FFI result ptr: {ptr:p} ({}i64)", ptr as i64);
1610 }
1611 ptr as _
1612 }
1613
1614 pub unsafe fn from_raw(ptr: i64, mem: &WasmLinearMem) -> Self {
1615 let result = Box::leak(Box::from_raw(crate::buf::compute_ptr(
1616 ptr as *mut Self,
1617 mem,
1618 )));
1619 #[cfg(feature = "trace")]
1620 {
1621 tracing::trace!(
1622 "got FFI result @ {ptr} ({:p}) -> {result:?}",
1623 ptr as *mut Self
1624 );
1625 }
1626 *result
1627 }
1628
1629 #[cfg(feature = "trace")]
1630 fn log_input<T: std::fmt::Debug>(&self, serialized: &[u8], value: &T, ptr: *mut u8) {
1631 tracing::trace!(
1632 "got result through FFI; addr: {:p} ({}i64, mapped: {ptr:p})
1633 serialized: {serialized:?}
1634 value: {value:?}",
1635 self.ptr as *mut u8,
1636 self.ptr
1637 );
1638 }
1639 }
1640
1641 macro_rules! conversion {
1642 ($value:ty: $kind:expr) => {
1643 impl From<$value> for ContractInterfaceResult {
1644 fn from(value: $value) -> Self {
1645 let kind = $kind as i32;
1646 let serialized = bincode::serialize(&value).unwrap();
1650 let size = serialized.len() as _;
1651 let ptr = serialized.as_ptr();
1652 #[cfg(feature = "trace")] {
1653 tracing::trace!(
1654 "sending result through FFI; addr: {ptr:p} ({}),\n serialized: {serialized:?}\n value: {value:?}",
1655 ptr as i64
1656 );
1657 }
1658 std::mem::forget(serialized);
1659 Self { kind, ptr: ptr as i64, size }
1660 }
1661 }
1662 };
1663 }
1664
1665 conversion!(Result<ValidateResult, ContractError>: ResultKind::ValidateState);
1666 conversion!(Result<bool, ContractError>: ResultKind::ValidateDelta);
1667 conversion!(Result<UpdateModification<'static>, ContractError>: ResultKind::UpdateState);
1668 conversion!(Result<StateSummary<'static>, ContractError>: ResultKind::SummarizeState);
1669 conversion!(Result<StateDelta<'static>, ContractError>: ResultKind::StateDelta);
1670}
1671
1672#[cfg(all(test, target_family = "unix"))]
1673mod test {
1674 use super::*;
1675 use once_cell::sync::Lazy;
1676 use rand::{rngs::SmallRng, Rng, SeedableRng};
1677
1678 static RND_BYTES: Lazy<[u8; 1024]> = Lazy::new(|| {
1679 let mut bytes = [0; 1024];
1680 let mut rng = SmallRng::from_entropy();
1681 rng.fill(&mut bytes);
1682 bytes
1683 });
1684
1685 #[test]
1686 fn key_encoding() -> Result<(), Box<dyn std::error::Error>> {
1687 let code = ContractCode::from(vec![1, 2, 3]);
1688 let expected = ContractKey::from((Parameters::from(vec![]), &code));
1689 let decoded = ContractKey::decode(code.hash_str(), [].as_ref().into())?;
1695 assert_eq!(expected, decoded);
1696 assert_eq!(expected.code_hash(), decoded.code_hash());
1697 Ok(())
1698 }
1699
1700 #[test]
1701 fn key_ser() -> Result<(), Box<dyn std::error::Error>> {
1702 let mut gen = arbitrary::Unstructured::new(&*RND_BYTES);
1703 let expected: ContractKey = gen.arbitrary()?;
1704 let encoded = bs58::encode(expected.bytes()).into_string();
1705 let serialized = bincode::serialize(&expected)?;
1708 let deserialized: ContractKey = bincode::deserialize(&serialized)?;
1709 let decoded = bs58::encode(deserialized.bytes()).into_string();
1710 assert_eq!(encoded, decoded);
1711 assert_eq!(deserialized, expected);
1712 Ok(())
1713 }
1714
1715 #[test]
1716 fn contract_ser() -> Result<(), Box<dyn std::error::Error>> {
1717 let mut gen = arbitrary::Unstructured::new(&*RND_BYTES);
1718 let expected: Contract = gen.arbitrary()?;
1719
1720 let serialized = bincode::serialize(&expected)?;
1721 let deserialized: Contract = bincode::deserialize(&serialized)?;
1722 assert_eq!(deserialized, expected);
1723 Ok(())
1724 }
1725}