1use std::borrow::Cow;
8use std::collections::btree_set::Iter;
9use std::collections::{BTreeMap, BTreeSet};
10use std::fmt::{Debug, Formatter};
11use std::mem;
12use std::ptr::NonNull;
13use std::sync::{Arc, mpsc};
14
15use bytecheck::CheckBytes;
16use dusk_wasmtime::{
17 Engine, LinearMemory, MemoryCreator, MemoryType, Module as WasmtimeModule,
18};
19use piecrust_uplink::{
20 ARGBUF_LEN, CONTRACT_ID_BYTES, ContractId, Event, SCRATCH_BUF_BYTES,
21};
22use rkyv::ser::Serializer;
23use rkyv::ser::serializers::{
24 BufferScratch, BufferSerializer, CompositeSerializer,
25};
26use rkyv::validation::validators::DefaultValidator;
27use rkyv::{Archive, Deserialize, Infallible, Serialize, check_archived_root};
28
29use crate::call_tree::{CallTree, CallTreeElem};
30use crate::contract::{ContractData, ContractMetadata, WrappedContract};
31use crate::error::Error::{self, InitalizationError, PersistenceError};
32use crate::instance::WrappedInstance;
33use crate::store::{ContractSession, PAGE_SIZE, PageOpening};
34use crate::types::StandardBufSerializer;
35use crate::vm::{HostQueries, HostQuery};
36
37const MAX_META_SIZE: usize = ARGBUF_LEN;
38pub(crate) const MAX_CALL_DEPTH: usize = 48;
42const _: () = assert!(MAX_CALL_DEPTH <= ARGBUF_LEN / CONTRACT_ID_BYTES);
43pub const INIT_METHOD: &str = "init";
44
45pub struct Session {
57 engine: Engine,
58 inner: NonNull<SessionInner>,
59 original: bool,
60}
61
62unsafe impl Send for Session {}
63
64impl Debug for Session {
65 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
66 f.debug_struct("Session")
67 .field("inner", &self.inner)
68 .field("original", &self.original)
69 .finish()
70 }
71}
72
73impl Drop for Session {
76 fn drop(&mut self) {
77 if self.original {
78 self.clear_call_tree_and_instances();
81
82 unsafe {
85 let _ = Box::from_raw(self.inner.as_ptr());
86 }
87 }
88 }
89}
90
91#[cfg(feature = "call-hook")]
97pub type CallHook =
98 Box<dyn Fn(&ContractId, &str, &[u8]) -> Result<(), String> + Send + Sync>;
99
100struct SessionInner {
101 current: ContractId,
102
103 call_tree: CallTree,
104 instances: BTreeMap<ContractId, Box<WrappedInstance>>,
105 compiled_modules: BTreeMap<ContractId, WasmtimeModule>,
106 debug: Vec<String>,
107 data: SessionData,
108
109 contract_session: ContractSession,
110 host_queries: HostQueries,
111 buffer: Vec<u8>,
112
113 feeder: Option<mpsc::Sender<Vec<u8>>>,
114 events: Vec<Event>,
115
116 #[cfg(feature = "call-hook")]
117 call_hook: Option<CallHook>,
118}
119
120impl Debug for SessionInner {
121 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
122 f.debug_struct("SessionInner")
123 .field("current", &self.current)
124 .field("call_tree", &self.call_tree)
125 .field("instances_len", &self.instances.len())
126 .field("compiled_modules_len", &self.compiled_modules.len())
127 .field("debug_len", &self.debug.len())
128 .field("data", &self.data)
129 .field("buffer_len", &self.buffer.len())
130 .field("events_len", &self.events.len())
131 .finish()
132 }
133}
134
135struct SessionMemoryCreator {
136 inner: NonNull<SessionInner>,
137}
138
139unsafe impl Send for SessionMemoryCreator {}
140
141unsafe impl Sync for SessionMemoryCreator {}
142
143unsafe impl MemoryCreator for SessionMemoryCreator {
144 fn new_memory(
147 &self,
148 _ty: MemoryType,
149 minimum: usize,
150 _maximum: Option<usize>,
151 _reserved_size_in_bytes: Option<usize>,
152 _guard_size_in_bytes: usize,
153 ) -> Result<Box<dyn LinearMemory>, String> {
154 let inner = unsafe { &mut *self.inner.as_ptr() };
157 let contract = inner.current;
158
159 let contract_data =
160 inner.contract_session.contract(contract).map_err(|err| {
161 format!("Failed to get contract from session: {err:?}")
162 })?;
163
164 let mut memory = contract_data
165 .expect("Contract data should exist at this point")
166 .memory;
167
168 if memory.is_new() {
169 memory.set_current_len(minimum);
170 }
171
172 Ok(Box::new(memory))
173 }
174}
175
176impl Session {
177 fn inner(&self) -> &SessionInner {
178 unsafe { self.inner.as_ref() }
179 }
180
181 fn inner_mut(&mut self) -> &mut SessionInner {
182 unsafe { self.inner.as_mut() }
183 }
184
185 pub(crate) fn new(
186 engine: Engine,
187 contract_session: ContractSession,
188 host_queries: HostQueries,
189 data: SessionData,
190 ) -> Self {
191 let inner = SessionInner {
192 current: ContractId::from_bytes([0; CONTRACT_ID_BYTES]),
193 call_tree: CallTree::new(),
194 instances: BTreeMap::new(),
195 compiled_modules: BTreeMap::new(),
196 debug: vec![],
197 data,
198 contract_session,
199 host_queries,
200 buffer: vec![0; PAGE_SIZE],
201 feeder: None,
202 events: vec![],
203 #[cfg(feature = "call-hook")]
204 call_hook: None,
205 };
206
207 let inner = Box::leak(Box::new(inner));
209
210 let mut session = Self {
211 engine: engine.clone(),
212 inner: NonNull::from(inner),
213 original: true,
214 };
215
216 let mut config = engine.config().clone();
217 config.with_host_memory(Arc::new(SessionMemoryCreator {
218 inner: session.inner,
219 }));
220
221 session.engine = Engine::new(&config)
222 .expect("Engine configuration is set at compile time");
223
224 session
225 }
226
227 pub(crate) fn clone(&self) -> Self {
234 Self {
235 engine: self.engine.clone(),
236 inner: self.inner,
237 original: false,
238 }
239 }
240
241 pub(crate) fn engine(&self) -> &Engine {
243 &self.engine
244 }
245
246 pub fn deploy<'a, A, R, D>(
272 &mut self,
273 bytecode: &[u8],
274 deploy_data: D,
275 gas_limit: u64,
276 ) -> Result<(ContractId, Option<CallReceipt<R>>), Error>
277 where
278 A: 'a + for<'b> Serialize<StandardBufSerializer<'b>>,
279 R: Archive,
280 R::Archived: Deserialize<R, Infallible>
281 + for<'b> CheckBytes<DefaultValidator<'b>>,
282 D: Into<ContractData<'a, A>>,
283 {
284 let deploy_data = deploy_data.into();
285
286 let mut init_arg = None;
287 if let Some(arg) = deploy_data.init_arg {
288 let mut sbuf = [0u8; SCRATCH_BUF_BYTES];
289 let scratch = BufferScratch::new(&mut sbuf);
290 let ser = BufferSerializer::new(&mut self.inner_mut().buffer[..]);
291 let mut ser = CompositeSerializer::new(ser, scratch, Infallible);
292
293 ser.serialize_value(arg)?;
294 let pos = ser.pos();
295
296 init_arg = Some(self.inner().buffer[0..pos].to_vec());
297 }
298
299 let (contract_id, receipt) = self.deploy_raw(
300 deploy_data.contract_id,
301 bytecode,
302 init_arg,
303 deploy_data
304 .owner
305 .expect("Owner must be specified when deploying a contract"),
306 gas_limit,
307 )?;
308
309 let receipt = receipt.map(|r| r.deserialize()).transpose()?;
310 Ok((contract_id, receipt))
311 }
312
313 #[allow(clippy::type_complexity)]
336 pub fn deploy_raw(
337 &mut self,
338 contract_id: Option<ContractId>,
339 bytecode: &[u8],
340 init_arg: Option<Vec<u8>>,
341 owner: Vec<u8>,
342 gas_limit: u64,
343 ) -> Result<(ContractId, Option<CallReceipt<Vec<u8>>>), Error> {
344 let contract_id = contract_id.unwrap_or({
345 let hash = blake3::hash(bytecode);
346 ContractId::from_bytes(hash.into())
347 });
348 let receipt =
349 self.do_deploy(contract_id, bytecode, init_arg, owner, gas_limit)?;
350
351 Ok((contract_id, receipt))
352 }
353
354 #[allow(clippy::too_many_arguments)]
355 fn do_deploy(
356 &mut self,
357 contract_id: ContractId,
358 bytecode: &[u8],
359 arg: Option<Vec<u8>>,
360 owner: Vec<u8>,
361 gas_limit: u64,
362 ) -> Result<Option<CallReceipt<Vec<u8>>>, Error> {
363 if self
364 .inner_mut()
365 .contract_session
366 .contract_deployed(contract_id)
367 {
368 return Err(InitalizationError(
369 "Deployed error already exists".into(),
370 ));
371 }
372
373 let wrapped_contract =
374 WrappedContract::new(&self.engine, bytecode, None::<&[u8]>)?;
375 let contract_metadata = ContractMetadata { contract_id, owner };
376 let metadata_bytes = Self::serialize_data(&contract_metadata)?;
377
378 self.inner_mut()
379 .contract_session
380 .deploy(
381 contract_id,
382 bytecode,
383 wrapped_contract.as_bytes(),
384 contract_metadata,
385 metadata_bytes.as_slice(),
386 )
387 .map_err(|err| PersistenceError(Arc::new(err)))?;
388 self.inner_mut().compiled_modules.remove(&contract_id);
389
390 let instantiate = || {
391 self.create_instance(contract_id)?;
392 let has_init = self
393 .instance(&contract_id)
394 .expect("instance should exist")
395 .is_function_exported(INIT_METHOD);
396
397 if has_init {
398 let arg = arg.unwrap_or_default();
404 let (data, gas_spent, call_tree) =
405 self.call_inner(contract_id, INIT_METHOD, arg, gas_limit)?;
406 let events = mem::take(&mut self.inner_mut().events);
407 return Ok(Some(CallReceipt {
408 gas_limit,
409 gas_spent,
410 events,
411 call_tree,
412 data,
413 }));
414 }
415
416 Ok(None)
417 };
418
419 instantiate().inspect_err(|_| {
420 self.inner_mut()
421 .contract_session
422 .remove_contract(&contract_id);
423 self.inner_mut().compiled_modules.remove(&contract_id);
424 })
425 }
426
427 pub fn call<A, R>(
439 &mut self,
440 contract: ContractId,
441 fn_name: &str,
442 fn_arg: &A,
443 gas_limit: u64,
444 ) -> Result<CallReceipt<R>, Error>
445 where
446 A: for<'b> Serialize<StandardBufSerializer<'b>>,
447 A::Archived: for<'b> CheckBytes<DefaultValidator<'b>>,
448 R: Archive,
449 R::Archived: Deserialize<R, Infallible>
450 + for<'b> CheckBytes<DefaultValidator<'b>>,
451 {
452 if fn_name == INIT_METHOD {
453 return Err(InitalizationError("init call not allowed".into()));
454 }
455
456 let mut sbuf = [0u8; SCRATCH_BUF_BYTES];
457 let scratch = BufferScratch::new(&mut sbuf);
458 let ser = BufferSerializer::new(&mut self.inner_mut().buffer[..]);
459 let mut ser = CompositeSerializer::new(ser, scratch, Infallible);
460
461 ser.serialize_value(fn_arg)?;
462 let pos = ser.pos();
463
464 let receipt = self.call_raw(
465 contract,
466 fn_name,
467 self.inner().buffer[..pos].to_vec(),
468 gas_limit,
469 )?;
470
471 receipt.deserialize()
472 }
473
474 pub fn call_raw<V: Into<Vec<u8>>>(
484 &mut self,
485 contract: ContractId,
486 fn_name: &str,
487 fn_arg: V,
488 gas_limit: u64,
489 ) -> Result<CallReceipt<Vec<u8>>, Error> {
490 if fn_name == INIT_METHOD {
491 return Err(InitalizationError("init call not allowed".into()));
492 }
493
494 let (data, gas_spent, call_tree) =
495 self.call_inner(contract, fn_name, fn_arg.into(), gas_limit)?;
496 let events = mem::take(&mut self.inner_mut().events);
497
498 Ok(CallReceipt {
499 gas_limit,
500 gas_spent,
501 events,
502 call_tree,
503 data,
504 })
505 }
506
507 pub fn migrate<'a, A, D, F>(
532 mut self,
533 contract: ContractId,
534 bytecode: &[u8],
535 deploy_data: D,
536 deploy_gas_limit: u64,
537 closure: F,
538 ) -> Result<Self, Error>
539 where
540 A: 'a + for<'b> Serialize<StandardBufSerializer<'b>>,
541 D: Into<ContractData<'a, A>>,
542 F: FnOnce(ContractId, &mut Session) -> Result<(), Error>,
543 {
544 let mut new_contract_data = deploy_data.into();
545
546 if let Some(old_contract_data) = self
549 .inner_mut()
550 .contract_session
551 .contract(contract)
552 .map_err(|err| PersistenceError(Arc::new(err)))?
553 {
554 if new_contract_data.owner.is_none() {
555 new_contract_data.owner =
556 Some(old_contract_data.metadata.data().owner.clone());
557 }
558 }
559
560 let (new_contract, _init_receipt) = self.deploy::<_, (), _>(
561 bytecode,
562 new_contract_data,
563 deploy_gas_limit,
564 )?;
565
566 closure(new_contract, &mut self)?;
567
568 self.inner_mut()
569 .contract_session
570 .replace(contract, new_contract)?;
571 self.inner_mut().compiled_modules.remove(&contract);
572 self.inner_mut().compiled_modules.remove(&new_contract);
573
574 Ok(self)
575 }
576
577 pub fn feeder_call<A, R>(
585 &mut self,
586 contract: ContractId,
587 fn_name: &str,
588 fn_arg: &A,
589 gas_limit: u64,
590 feeder: mpsc::Sender<Vec<u8>>,
591 ) -> Result<CallReceipt<R>, Error>
592 where
593 A: for<'b> Serialize<StandardBufSerializer<'b>>,
594 A::Archived: for<'b> CheckBytes<DefaultValidator<'b>>,
595 R: Archive,
596 R::Archived: Deserialize<R, Infallible>
597 + for<'b> CheckBytes<DefaultValidator<'b>>,
598 {
599 self.inner_mut().feeder = Some(feeder);
600 let r = self.call(contract, fn_name, fn_arg, gas_limit);
601 self.inner_mut().feeder = None;
602 r
603 }
604
605 pub fn feeder_call_raw<V: Into<Vec<u8>>>(
613 &mut self,
614 contract: ContractId,
615 fn_name: &str,
616 fn_arg: V,
617 gas_limit: u64,
618 feeder: mpsc::Sender<Vec<u8>>,
619 ) -> Result<CallReceipt<Vec<u8>>, Error> {
620 self.inner_mut().feeder = Some(feeder);
621 let r = self.call_raw(contract, fn_name, fn_arg, gas_limit);
622 self.inner_mut().feeder = None;
623 r
624 }
625
626 pub fn memory_len(
630 &mut self,
631 contract_id: ContractId,
632 ) -> Result<Option<usize>, Error> {
633 Ok(self
634 .inner_mut()
635 .contract_session
636 .contract(contract_id)
637 .map_err(|err| PersistenceError(Arc::new(err)))?
638 .map(|data| data.memory.current_len()))
639 }
640
641 pub(crate) fn instance(
642 &mut self,
643 contract_id: &ContractId,
644 ) -> Option<&mut WrappedInstance> {
645 self.inner_mut()
646 .instances
647 .get_mut(contract_id)
648 .map(Box::as_mut)
649 }
650
651 fn clear_call_tree_and_instances(&mut self) {
652 self.inner_mut().call_tree.clear();
653 self.inner_mut().instances.clear();
654 }
655
656 pub fn root(&self) -> [u8; 32] {
663 self.inner().contract_session.root().into()
664 }
665
666 pub fn memory_pages(
676 &self,
677 contract: ContractId,
678 ) -> Option<impl Iterator<Item = (usize, &[u8], PageOpening)>> {
679 self.inner().contract_session.memory_pages(contract)
680 }
681
682 pub(crate) fn push_event(&mut self, event: Event) {
683 self.inner_mut().events.push(event);
684 }
685
686 pub(crate) fn event_checkpoint(&self) -> usize {
687 self.inner().events.len()
688 }
689
690 pub(crate) fn revert_events_from(&mut self, checkpoint: usize) {
691 for event in self.inner_mut().events.iter_mut().skip(checkpoint) {
692 event.reverted = true;
693 }
694 }
695
696 pub(crate) fn push_feed(&mut self, data: Vec<u8>) -> Result<(), Error> {
697 let feed = self.inner().feeder.as_ref().ok_or(Error::MissingFeed)?;
698 feed.send(data).map_err(Error::FeedPulled)
699 }
700
701 fn new_instance(
702 &mut self,
703 contract_id: ContractId,
704 ) -> Result<WrappedInstance, Error> {
705 let store_data = self
706 .inner_mut()
707 .contract_session
708 .contract(contract_id)
709 .map_err(|err| PersistenceError(Arc::new(err)))?
710 .ok_or(Error::ContractDoesNotExist(contract_id))?;
711
712 let module = if let Some(module) =
713 self.inner().compiled_modules.get(&contract_id)
714 {
715 module.clone()
716 } else {
717 let module = unsafe {
718 WasmtimeModule::deserialize(
719 &self.engine,
720 store_data.module.serialize(),
721 )?
722 };
723 self.inner_mut()
724 .compiled_modules
725 .insert(contract_id, module.clone());
726 module
727 };
728
729 self.inner_mut().current = contract_id;
730
731 let instance = WrappedInstance::new(
732 self.clone(),
733 contract_id,
734 &module,
735 store_data.memory,
736 )?;
737
738 Ok(instance)
739 }
740
741 pub(crate) fn host_query_arc(
742 &self,
743 name: &str,
744 ) -> Option<Arc<dyn HostQuery>> {
745 self.inner().host_queries.get_arc(name)
746 }
747
748 pub(crate) fn nth_from_top(&self, n: usize) -> Option<CallTreeElem> {
749 self.inner().call_tree.nth_parent(n)
750 }
751
752 pub(crate) fn call_ids(&self) -> Vec<&ContractId> {
753 self.inner().call_tree.call_ids()
754 }
755
756 fn create_instance(
759 &mut self,
760 contract: ContractId,
761 ) -> Result<usize, Error> {
762 let instance = self.new_instance(contract)?;
763 if self.inner().instances.contains_key(&contract) {
764 panic!("Contract already in the stack: {contract:?}");
765 }
766
767 let mem_len = instance.mem_len();
768
769 self.inner_mut()
770 .instances
771 .insert(contract, Box::new(instance));
772 Ok(mem_len)
773 }
774
775 pub(crate) fn push_callstack(
776 &mut self,
777 contract_id: ContractId,
778 limit: u64,
779 ) -> Result<CallTreeElem, Error> {
780 let current_depth = self.inner().call_tree.depth();
781 if current_depth >= MAX_CALL_DEPTH {
782 return Err(Error::SessionError(
783 format!("Maximum call depth exceeded ({MAX_CALL_DEPTH})")
784 .into(),
785 ));
786 }
787
788 let mem_len =
789 if let Some(instance) = self.inner().instances.get(&contract_id) {
790 instance.mem_len()
791 } else {
792 self.create_instance(contract_id)?
793 };
794
795 self.inner_mut().call_tree.push(CallTreeElem {
796 contract_id,
797 limit,
798 spent: 0,
799 mem_len,
800 });
801
802 Ok(self
803 .inner()
804 .call_tree
805 .nth_parent(0)
806 .expect("We just pushed an element to the stack"))
807 }
808
809 pub(crate) fn move_up_call_tree(&mut self, spent: u64) {
810 self.inner_mut().call_tree.move_up(spent);
811 }
812
813 pub(crate) fn move_up_prune_call_tree(&mut self) {
814 self.inner_mut().call_tree.move_up_prune();
815 }
816
817 pub(crate) fn revert_callstack(&mut self) -> Result<(), std::io::Error> {
818 let call_tree: Vec<_> =
819 self.inner().call_tree.iter().copied().collect();
820 for elem in call_tree {
821 let instance = self
822 .instance(&elem.contract_id)
823 .expect("instance should exist");
824 instance.revert()?;
825 instance.set_len(elem.mem_len);
826 }
827
828 Ok(())
829 }
830
831 pub fn commit(mut self) -> Result<[u8; 32], Error> {
834 self.inner_mut()
835 .contract_session
836 .commit()
837 .map(Into::into)
838 .map_err(|err| PersistenceError(Arc::new(err)))
839 }
840
841 #[cfg(feature = "debug")]
842 pub(crate) fn register_debug<M: Into<String>>(&mut self, msg: M) {
843 self.inner_mut().debug.push(msg.into());
844 }
845
846 pub fn with_debug<C, R>(&self, c: C) -> R
847 where
848 C: FnOnce(&[String]) -> R,
849 {
850 c(&self.inner().debug)
851 }
852
853 pub fn meta(&self, name: &str) -> Option<Vec<u8>> {
855 self.inner().data.get(name)
856 }
857
858 pub fn set_meta<S, V>(
862 &mut self,
863 name: S,
864 value: V,
865 ) -> Result<Option<Vec<u8>>, Error>
866 where
867 S: Into<Cow<'static, str>>,
868 V: for<'a> Serialize<StandardBufSerializer<'a>>,
869 {
870 let data = Self::serialize_data(&value)?;
871 Ok(self.inner_mut().data.set(name, data))
872 }
873
874 pub fn remove_meta<S>(&mut self, name: S) -> Option<Vec<u8>>
878 where
879 S: Into<Cow<'static, str>>,
880 {
881 self.inner_mut().data.remove(name)
882 }
883
884 pub fn serialize_data<V>(value: &V) -> Result<Vec<u8>, Error>
885 where
886 V: for<'a> Serialize<StandardBufSerializer<'a>>,
887 {
888 let mut buf = [0u8; MAX_META_SIZE];
889 let mut sbuf = [0u8; SCRATCH_BUF_BYTES];
890
891 let ser = BufferSerializer::new(&mut buf[..]);
892 let scratch = BufferScratch::new(&mut sbuf);
893
894 let mut serializer =
895 StandardBufSerializer::new(ser, scratch, Infallible);
896 serializer.serialize_value(value)?;
897
898 let pos = serializer.pos();
899
900 Ok(buf[..pos].to_vec())
901 }
902
903 fn call_inner(
904 &mut self,
905 contract: ContractId,
906 fname: &str,
907 fdata: Vec<u8>,
908 limit: u64,
909 ) -> Result<(Vec<u8>, u64, CallTree), Error> {
910 let event_checkpoint = self.event_checkpoint();
911 let stack_element = self.push_callstack(contract, limit)?;
912 {
913 let instance = self
914 .instance(&stack_element.contract_id)
915 .expect("instance should exist");
916 instance
917 .snap()
918 .map_err(|err| Error::MemorySnapshotFailure {
919 reason: None,
920 io: Arc::new(err),
921 })?;
922 }
923
924 let ret_len = {
925 let instance = self
926 .instance(&stack_element.contract_id)
927 .expect("instance should exist");
928 let arg_len = instance.write_bytes_to_arg_buffer(&fdata)?;
929 instance
930 .call(fname, arg_len, limit)
931 .map_err(Error::normalize)
932 };
933
934 let ret_len = match ret_len {
935 Ok(ret_len) => ret_len,
936 Err(err) => {
937 let err = if let Err(io_err) = self.revert_callstack() {
938 Error::MemorySnapshotFailure {
939 reason: Some(Arc::new(err)),
940 io: Arc::new(io_err),
941 }
942 } else {
943 err
944 };
945 self.revert_events_from(event_checkpoint);
946 self.move_up_prune_call_tree();
947 self.clear_call_tree_and_instances();
948 return Err(err);
949 }
950 };
951
952 let (ret, spent) = {
953 let instance = self
954 .instance(&stack_element.contract_id)
955 .expect("instance should exist");
956 let ret = instance.read_bytes_from_arg_buffer(ret_len as u32);
957 let spent = limit - instance.get_remaining_gas();
958 (ret, spent)
959 };
960
961 let call_tree: Vec<_> =
962 self.inner().call_tree.iter().copied().collect();
963 for elem in call_tree {
964 let instance = self
965 .instance(&elem.contract_id)
966 .expect("instance should exist");
967 instance
968 .apply()
969 .map_err(|err| Error::MemorySnapshotFailure {
970 reason: None,
971 io: Arc::new(err),
972 })?;
973 }
974
975 let mut call_tree = CallTree::new();
976 mem::swap(&mut self.inner_mut().call_tree, &mut call_tree);
977 call_tree.update_spent(spent);
978
979 self.clear_call_tree_and_instances();
980
981 Ok((ret, spent, call_tree))
982 }
983
984 pub fn contract_metadata(
985 &mut self,
986 contract_id: &ContractId,
987 ) -> Option<&ContractMetadata> {
988 self.inner_mut()
989 .contract_session
990 .contract_metadata(contract_id)
991 }
992
993 #[cfg(feature = "call-hook")]
998 pub fn set_call_hook(&mut self, hook: CallHook) -> Option<CallHook> {
999 self.inner_mut().call_hook.replace(hook)
1000 }
1001
1002 #[cfg(feature = "call-hook")]
1004 pub fn clear_call_hook(&mut self) -> Option<CallHook> {
1005 self.inner_mut().call_hook.take()
1006 }
1007
1008 #[cfg(feature = "call-hook")]
1013 pub(crate) fn call_hook(
1014 &self,
1015 callee: &ContractId,
1016 fn_name: &str,
1017 arg: &[u8],
1018 ) -> Result<(), String> {
1019 if let Some(hook) = &self.inner().call_hook {
1020 hook(callee, fn_name, arg)
1021 } else {
1022 Ok(())
1023 }
1024 }
1025}
1026
1027#[derive(Debug)]
1034pub struct CallReceipt<T> {
1035 pub gas_spent: u64,
1037 pub gas_limit: u64,
1039
1040 pub events: Vec<Event>,
1042 pub call_tree: CallTree,
1044
1045 pub data: T,
1047}
1048
1049impl CallReceipt<Vec<u8>> {
1050 fn deserialize<T>(self) -> Result<CallReceipt<T>, Error>
1053 where
1054 T: Archive,
1055 T::Archived: Deserialize<T, Infallible>
1056 + for<'b> CheckBytes<DefaultValidator<'b>>,
1057 {
1058 let ta = check_archived_root::<T>(&self.data[..])?;
1059 let data = ta.deserialize(&mut Infallible)?;
1060
1061 Ok(CallReceipt {
1062 gas_spent: self.gas_spent,
1063 gas_limit: self.gas_limit,
1064 events: self.events,
1065 call_tree: self.call_tree,
1066 data,
1067 })
1068 }
1069}
1070
1071#[derive(Debug, Default)]
1072pub struct SessionData {
1073 data: BTreeMap<Cow<'static, str>, Vec<u8>>,
1074 pub base: Option<[u8; 32]>,
1075 excluded_host_queries: BTreeSet<String>,
1076}
1077
1078impl SessionData {
1079 pub fn builder() -> SessionDataBuilder {
1080 SessionDataBuilder {
1081 data: BTreeMap::new(),
1082 base: None,
1083 excluded_host_queries: BTreeSet::new(),
1084 }
1085 }
1086
1087 fn get(&self, name: &str) -> Option<Vec<u8>> {
1088 self.data.get(name).cloned()
1089 }
1090
1091 fn set<S>(&mut self, name: S, data: Vec<u8>) -> Option<Vec<u8>>
1092 where
1093 S: Into<Cow<'static, str>>,
1094 {
1095 self.data.insert(name.into(), data)
1096 }
1097
1098 fn remove<S>(&mut self, name: S) -> Option<Vec<u8>>
1099 where
1100 S: Into<Cow<'static, str>>,
1101 {
1102 self.data.remove(&name.into())
1103 }
1104
1105 pub fn excluded_host_queries(&self) -> Iter<String> {
1106 self.excluded_host_queries.iter()
1107 }
1108}
1109
1110impl From<SessionDataBuilder> for SessionData {
1111 fn from(builder: SessionDataBuilder) -> Self {
1112 builder.build()
1113 }
1114}
1115
1116pub struct SessionDataBuilder {
1117 data: BTreeMap<Cow<'static, str>, Vec<u8>>,
1118 base: Option<[u8; 32]>,
1119 excluded_host_queries: BTreeSet<String>,
1120}
1121
1122impl SessionDataBuilder {
1123 pub fn insert<S, V>(mut self, name: S, value: V) -> Result<Self, Error>
1124 where
1125 S: Into<Cow<'static, str>>,
1126 V: for<'a> Serialize<StandardBufSerializer<'a>>,
1127 {
1128 let data = Session::serialize_data(&value)?;
1129 self.data.insert(name.into(), data);
1130 Ok(self)
1131 }
1132
1133 pub fn base(mut self, base: [u8; 32]) -> Self {
1134 self.base = Some(base);
1135 self
1136 }
1137
1138 pub fn exclude_hq(mut self, name: String) -> Self {
1139 self.excluded_host_queries.insert(name);
1140 self
1141 }
1142
1143 fn build(&self) -> SessionData {
1144 SessionData {
1145 data: self.data.clone(),
1146 base: self.base,
1147 excluded_host_queries: self.excluded_host_queries.clone(),
1148 }
1149 }
1150}