1use std::{collections::BTreeSet, convert::TryFrom};
2
3use serde::Serialize;
4use thiserror::Error;
5
6use casper_storage::{data_access_layer::TransferResult, tracking_copy::TrackingCopyCache};
7use casper_types::{
8 account::AccountHash,
9 bytesrepr::Bytes,
10 contract_messages::Messages,
11 execution::{Effects, TransformKindV2},
12 BlockHash, BlockTime, CLValue, DeployHash, Digest, ExecutableDeployItem, Gas, InitiatorAddr,
13 Key, Phase, PricingMode, ProtocolVersion, RuntimeArgs, TransactionEntryPoint, TransactionHash,
14 TransactionInvocationTarget, TransactionTarget, TransactionV1Hash, Transfer, URefAddr, U512,
15};
16
17use crate::engine_state::Error as EngineError;
18
19const DEFAULT_ENTRY_POINT: &str = "call";
20
21pub struct SessionDataDeploy<'a> {
23 deploy_hash: &'a DeployHash,
24 session: &'a ExecutableDeployItem,
25 initiator_addr: &'a InitiatorAddr,
26 signers: BTreeSet<AccountHash>,
27 is_standard_payment: bool,
28}
29
30impl<'a> SessionDataDeploy<'a> {
31 pub fn new(
33 deploy_hash: &'a DeployHash,
34 session: &'a ExecutableDeployItem,
35 initiator_addr: &'a InitiatorAddr,
36 signers: BTreeSet<AccountHash>,
37 is_standard_payment: bool,
38 ) -> Self {
39 Self {
40 deploy_hash,
41 session,
42 initiator_addr,
43 signers,
44 is_standard_payment,
45 }
46 }
47
48 pub fn deploy_hash(&self) -> &DeployHash {
50 self.deploy_hash
51 }
52
53 pub fn session(&self) -> &ExecutableDeployItem {
55 self.session
56 }
57
58 pub fn initiator_addr(&self) -> &InitiatorAddr {
60 self.initiator_addr
61 }
62
63 pub fn signers(&self) -> BTreeSet<AccountHash> {
65 self.signers.clone()
66 }
67}
68
69pub struct SessionDataV1<'a> {
71 args: &'a RuntimeArgs,
72 target: &'a TransactionTarget,
73 entry_point: &'a TransactionEntryPoint,
74 is_install_upgrade: bool,
75 hash: &'a TransactionV1Hash,
76 pricing_mode: &'a PricingMode,
77 initiator_addr: &'a InitiatorAddr,
78 signers: BTreeSet<AccountHash>,
79 is_standard_payment: bool,
80}
81
82impl<'a> SessionDataV1<'a> {
83 #[allow(clippy::too_many_arguments)]
84 pub fn new(
86 args: &'a RuntimeArgs,
87 target: &'a TransactionTarget,
88 entry_point: &'a TransactionEntryPoint,
89 is_install_upgrade: bool,
90 hash: &'a TransactionV1Hash,
91 pricing_mode: &'a PricingMode,
92 initiator_addr: &'a InitiatorAddr,
93 signers: BTreeSet<AccountHash>,
94 is_standard_payment: bool,
95 ) -> Self {
96 Self {
97 args,
98 target,
99 entry_point,
100 is_install_upgrade,
101 hash,
102 pricing_mode,
103 initiator_addr,
104 signers,
105 is_standard_payment,
106 }
107 }
108
109 pub fn args(&self) -> &RuntimeArgs {
111 self.args
112 }
113
114 pub fn target(&self) -> &TransactionTarget {
116 self.target
117 }
118
119 pub fn entry_point(&self) -> &TransactionEntryPoint {
121 self.entry_point
122 }
123
124 pub fn is_install_upgrade(&self) -> bool {
126 self.is_install_upgrade
127 }
128
129 pub fn hash(&self) -> &TransactionV1Hash {
131 self.hash
132 }
133
134 pub fn initiator_addr(&self) -> &InitiatorAddr {
136 self.initiator_addr
137 }
138
139 pub fn signers(&self) -> BTreeSet<AccountHash> {
141 self.signers.clone()
142 }
143
144 pub fn pricing_mode(&self) -> &PricingMode {
146 self.pricing_mode
147 }
148}
149
150pub enum SessionInputData<'a> {
152 DeploySessionData {
154 data: SessionDataDeploy<'a>,
156 },
157 SessionDataV1 {
159 data: SessionDataV1<'a>,
161 },
162}
163
164impl SessionInputData<'_> {
165 pub fn transaction_hash(&self) -> TransactionHash {
167 match self {
168 SessionInputData::DeploySessionData { data } => {
169 TransactionHash::Deploy(*data.deploy_hash())
170 }
171 SessionInputData::SessionDataV1 { data } => TransactionHash::V1(*data.hash()),
172 }
173 }
174
175 pub fn initiator_addr(&self) -> &InitiatorAddr {
177 match self {
178 SessionInputData::DeploySessionData { data } => data.initiator_addr(),
179 SessionInputData::SessionDataV1 { data } => data.initiator_addr(),
180 }
181 }
182
183 pub fn signers(&self) -> BTreeSet<AccountHash> {
185 match self {
186 SessionInputData::DeploySessionData { data } => data.signers(),
187 SessionInputData::SessionDataV1 { data } => data.signers(),
188 }
189 }
190
191 pub fn is_standard_payment(&self) -> bool {
193 match self {
194 SessionInputData::DeploySessionData { data } => data.is_standard_payment,
195 SessionInputData::SessionDataV1 { data } => data.is_standard_payment,
196 }
197 }
198
199 pub fn is_install_upgrade_allowed(&self) -> bool {
201 match self {
202 SessionInputData::DeploySessionData { .. } => true,
203 SessionInputData::SessionDataV1 { data } => data.is_install_upgrade,
204 }
205 }
206}
207
208#[derive(Clone, Eq, PartialEq, Error, Serialize, Debug)]
210pub enum InvalidRequest {
211 #[error("custom payment not found for {0}")]
213 CustomPaymentNotFound(TransactionHash),
214 #[error("unexpected variant for {0} attempting {1}")]
216 UnexpectedVariant(TransactionHash, String),
217 #[error("unsupported mode for {0} attempting {1}")]
219 UnsupportedMode(TransactionHash, String),
220 #[error("invalid entry point for {0} attempting {1}")]
222 InvalidEntryPoint(TransactionHash, String),
223 #[error("invalid target for {0} attempting {1}")]
225 InvalidTarget(TransactionHash, String),
226 #[error("invalid category for {0} attempting {1}")]
228 InvalidCategory(TransactionHash, String),
229}
230
231#[derive(Debug, Clone)]
232pub enum SessionKind {
233 InstallUpgradeBytecode,
234 GenericBytecode,
235}
236
237#[derive(Debug, Clone)]
239pub enum ExecutableItem {
240 Deploy(Bytes),
242 PaymentBytes(Bytes),
244 SessionBytes {
246 kind: SessionKind,
248 module_bytes: Bytes,
250 },
251 Invocation(TransactionInvocationTarget),
253}
254
255impl ExecutableItem {
256 pub fn is_install_upgrade_allowed(&self) -> bool {
258 match self {
259 ExecutableItem::Deploy(_) => true,
260 ExecutableItem::PaymentBytes(_) | ExecutableItem::Invocation(_) => false,
261 ExecutableItem::SessionBytes { kind, .. } => {
262 matches!(kind, SessionKind::InstallUpgradeBytecode)
263 }
264 }
265 }
266}
267
268#[derive(Copy, Clone, Debug)]
270pub struct BlockInfo {
271 pub state_hash: Digest,
273 pub block_time: BlockTime,
275 pub parent_block_hash: BlockHash,
277 pub block_height: u64,
279 pub protocol_version: ProtocolVersion,
281}
282
283impl BlockInfo {
284 pub fn new(
286 state_hash: Digest,
287 block_time: BlockTime,
288 parent_block_hash: BlockHash,
289 block_height: u64,
290 protocol_version: ProtocolVersion,
291 ) -> Self {
292 BlockInfo {
293 state_hash,
294 block_time,
295 parent_block_hash,
296 block_height,
297 protocol_version,
298 }
299 }
300
301 pub fn with_state_hash(&mut self, state_hash: Digest) {
303 self.state_hash = state_hash;
304 }
305
306 pub fn state_hash(&self) -> Digest {
308 self.state_hash
309 }
310
311 pub fn block_time(&self) -> BlockTime {
313 self.block_time
314 }
315
316 pub fn parent_block_hash(&self) -> BlockHash {
318 self.parent_block_hash
319 }
320
321 pub fn block_height(&self) -> u64 {
323 self.block_height
324 }
325
326 pub fn protocol_version(&self) -> ProtocolVersion {
328 self.protocol_version
329 }
330}
331
332#[derive(Debug)]
334pub struct WasmV1Request {
335 pub block_info: BlockInfo,
337 pub transaction_hash: TransactionHash,
339 pub gas_limit: Gas,
341 pub initiator_addr: InitiatorAddr,
343 pub executable_item: ExecutableItem,
345 pub entry_point: String,
347 pub args: RuntimeArgs,
349 pub authorization_keys: BTreeSet<AccountHash>,
351 pub phase: Phase,
353}
354
355impl WasmV1Request {
356 pub fn new_from_executable_deploy_item(
358 block_info: BlockInfo,
359 gas_limit: Gas,
360 transaction_hash: TransactionHash,
361 initiator_addr: InitiatorAddr,
362 authorization_keys: BTreeSet<AccountHash>,
363 session_item: &ExecutableDeployItem,
364 ) -> Result<Self, InvalidRequest> {
365 let executable_info =
366 build_session_info_for_executable_item(session_item, transaction_hash)?;
367 Ok(Self::new_from_executable_info(
368 block_info,
369 gas_limit,
370 transaction_hash,
371 initiator_addr,
372 authorization_keys,
373 executable_info,
374 ))
375 }
376
377 pub fn new_payment_from_executable_deploy_item(
379 block_info: BlockInfo,
380 gas_limit: Gas,
381 transaction_hash: TransactionHash,
382 initiator_addr: InitiatorAddr,
383 authorization_keys: BTreeSet<AccountHash>,
384 payment_item: &ExecutableDeployItem,
385 ) -> Result<Self, InvalidRequest> {
386 let executable_info =
387 build_payment_info_for_executable_item(payment_item, transaction_hash)?;
388 Ok(Self::new_from_executable_info(
389 block_info,
390 gas_limit,
391 transaction_hash,
392 initiator_addr,
393 authorization_keys,
394 executable_info,
395 ))
396 }
397
398 pub(crate) fn new_from_executable_info(
399 block_info: BlockInfo,
400 gas_limit: Gas,
401 transaction_hash: TransactionHash,
402 initiator_addr: InitiatorAddr,
403 authorization_keys: BTreeSet<AccountHash>,
404 executable_info: impl Executable,
405 ) -> Self {
406 let executable_item = executable_info.item();
407 Self {
408 block_info,
409 transaction_hash,
410 gas_limit,
411 initiator_addr,
412 authorization_keys,
413 executable_item,
414 entry_point: executable_info.entry_point().clone(),
415 args: executable_info.args().clone(),
416 phase: executable_info.phase(),
417 }
418 }
419
420 pub fn new_session(
422 block_info: BlockInfo,
423 gas_limit: Gas,
424 session_input_data: &SessionInputData,
425 ) -> Result<Self, InvalidRequest> {
426 let session_info = SessionInfo::try_from(session_input_data)?;
427 let transaction_hash = session_input_data.transaction_hash();
428 let initiator_addr = session_input_data.initiator_addr().clone();
429 let authorization_keys = session_input_data.signers().clone();
430 Ok(WasmV1Request::new_from_executable_info(
431 block_info,
432 gas_limit,
433 transaction_hash,
434 initiator_addr,
435 authorization_keys,
436 session_info,
437 ))
438 }
439
440 pub fn new_custom_payment(
442 block_info: BlockInfo,
443 gas_limit: Gas,
444 session_input_data: &SessionInputData,
445 ) -> Result<Self, InvalidRequest> {
446 let payment_info = PaymentInfo::try_from(session_input_data)?;
447 let transaction_hash = session_input_data.transaction_hash();
448 let initiator_addr = session_input_data.initiator_addr().clone();
449 let authorization_keys = session_input_data.signers().clone();
450 Ok(WasmV1Request::new_from_executable_info(
451 block_info,
452 gas_limit,
453 transaction_hash,
454 initiator_addr,
455 authorization_keys,
456 payment_info,
457 ))
458 }
459}
460
461#[derive(Clone, Debug)]
463pub struct WasmV1Result {
464 transfers: Vec<Transfer>,
466 limit: Gas,
468 consumed: Gas,
470 effects: Effects,
472 messages: Messages,
474 error: Option<EngineError>,
476 ret: Option<CLValue>,
478 cache: Option<TrackingCopyCache>,
480}
481
482impl WasmV1Result {
483 #[allow(clippy::too_many_arguments)]
485 pub fn new(
486 limit: Gas,
487 consumed: Gas,
488 effects: Effects,
489 transfers: Vec<Transfer>,
490 messages: Messages,
491 error: Option<EngineError>,
492 ret: Option<CLValue>,
493 cache: Option<TrackingCopyCache>,
494 ) -> Self {
495 WasmV1Result {
496 limit,
497 consumed,
498 effects,
499 transfers,
500 messages,
501 error,
502 ret,
503 cache,
504 }
505 }
506
507 pub fn error(&self) -> Option<&EngineError> {
509 self.error.as_ref()
510 }
511
512 pub fn transfers(&self) -> &Vec<Transfer> {
514 &self.transfers
515 }
516
517 pub fn limit(&self) -> Gas {
519 self.limit
520 }
521
522 pub fn consumed(&self) -> Gas {
524 self.consumed
525 }
526
527 pub fn effects(&self) -> &Effects {
529 &self.effects
530 }
531
532 pub fn cache(&self) -> Option<&TrackingCopyCache> {
534 self.cache.as_ref()
535 }
536
537 pub fn messages(&self) -> &Messages {
539 &self.messages
540 }
541
542 pub fn ret(&self) -> Option<&CLValue> {
544 self.ret.as_ref()
545 }
546
547 pub fn root_not_found(gas_limit: Gas, state_hash: Digest) -> Self {
549 WasmV1Result {
550 transfers: Vec::default(),
551 effects: Effects::new(),
552 messages: Vec::default(),
553 limit: gas_limit,
554 consumed: Gas::zero(),
555 error: Some(EngineError::RootNotFound(state_hash)),
556 ret: None,
557 cache: None,
558 }
559 }
560
561 pub fn precondition_failure(gas_limit: Gas, error: EngineError) -> Self {
563 WasmV1Result {
564 transfers: Vec::default(),
565 effects: Effects::new(),
566 messages: Vec::default(),
567 limit: gas_limit,
568 consumed: Gas::zero(),
569 error: Some(error),
570 ret: None,
571 cache: None,
572 }
573 }
574
575 pub fn invalid_executable_item(gas_limit: Gas, error: InvalidRequest) -> Self {
577 WasmV1Result {
578 transfers: Vec::default(),
579 effects: Effects::new(),
580 messages: Vec::default(),
581 limit: gas_limit,
582 consumed: Gas::zero(),
583 error: Some(EngineError::InvalidExecutableItem(error)),
584 ret: None,
585 cache: None,
586 }
587 }
588
589 pub fn has_precondition_failure(&self) -> bool {
594 self.error.is_some() && self.consumed == Gas::zero() && self.effects.is_empty()
595 }
596
597 pub fn from_transfer_result(transfer_result: TransferResult, consumed: Gas) -> Option<Self> {
599 match transfer_result {
603 TransferResult::RootNotFound => None,
604 TransferResult::Success {
605 transfers,
606 effects,
607 cache,
608 } => Some(WasmV1Result {
609 transfers,
610 limit: consumed,
611 consumed,
612 effects,
613 messages: Messages::default(),
614 error: None,
615 ret: None,
616 cache: Some(cache),
617 }),
618 TransferResult::Failure(te) => {
619 Some(WasmV1Result {
620 transfers: vec![],
621 limit: consumed,
622 consumed,
623 effects: Effects::default(), messages: Messages::default(),
625 error: Some(EngineError::Transfer(te)),
626 ret: None,
627 cache: None,
628 })
629 }
630 }
631 }
632
633 pub fn balance_increased_by_amount(&self, addr: URefAddr, amount: U512) -> bool {
636 if self.effects.is_empty() || self.effects.transforms().is_empty() {
637 return false;
638 }
639
640 let key = Key::Balance(addr);
641 if let Some(transform) = self.effects.transforms().iter().find(|x| x.key() == &key) {
642 if let TransformKindV2::AddUInt512(added) = transform.kind() {
643 return *added == amount;
644 }
645 }
646 false
647 }
648}
649
650struct ExecutableInfo {
652 item: ExecutableItem,
653 entry_point: String,
654 args: RuntimeArgs,
655}
656
657pub(crate) trait Executable {
658 fn item(&self) -> ExecutableItem;
659 fn entry_point(&self) -> &String;
660 fn args(&self) -> &RuntimeArgs;
661 fn phase(&self) -> Phase;
662}
663
664struct SessionInfo(ExecutableInfo);
666
667impl Executable for SessionInfo {
668 fn item(&self) -> ExecutableItem {
669 self.0.item.clone()
670 }
671
672 fn entry_point(&self) -> &String {
673 &self.0.entry_point
674 }
675
676 fn args(&self) -> &RuntimeArgs {
677 &self.0.args
678 }
679
680 fn phase(&self) -> Phase {
681 Phase::Session
682 }
683}
684
685impl TryFrom<&SessionInputData<'_>> for PaymentInfo {
686 type Error = InvalidRequest;
687
688 fn try_from(input_data: &SessionInputData) -> Result<Self, Self::Error> {
689 match input_data {
690 SessionInputData::DeploySessionData { data } => PaymentInfo::try_from(data),
691 SessionInputData::SessionDataV1 { data } => PaymentInfo::try_from(data),
692 }
693 }
694}
695
696impl TryFrom<&SessionInputData<'_>> for SessionInfo {
697 type Error = InvalidRequest;
698
699 fn try_from(input_data: &SessionInputData) -> Result<Self, Self::Error> {
700 match input_data {
701 SessionInputData::DeploySessionData { data } => SessionInfo::try_from(data),
702 SessionInputData::SessionDataV1 { data } => SessionInfo::try_from(data),
703 }
704 }
705}
706
707impl TryFrom<&SessionDataDeploy<'_>> for SessionInfo {
708 type Error = InvalidRequest;
709
710 fn try_from(deploy_data: &SessionDataDeploy) -> Result<Self, Self::Error> {
711 let transaction_hash = TransactionHash::Deploy(*deploy_data.deploy_hash());
712 let session_item = deploy_data.session();
713 build_session_info_for_executable_item(session_item, transaction_hash)
714 }
715}
716
717fn build_session_info_for_executable_item(
718 session_item: &ExecutableDeployItem,
719 transaction_hash: TransactionHash,
720) -> Result<SessionInfo, InvalidRequest> {
721 let session: ExecutableItem;
722 let session_entry_point: String;
723 let session_args: RuntimeArgs;
724 match session_item {
725 ExecutableDeployItem::ModuleBytes { module_bytes, args } => {
726 session = ExecutableItem::Deploy(module_bytes.clone());
727 session_entry_point = DEFAULT_ENTRY_POINT.to_string();
728 session_args = args.clone();
729 }
730 ExecutableDeployItem::StoredContractByHash {
731 hash,
732 entry_point,
733 args,
734 } => {
735 session = ExecutableItem::Invocation(
736 TransactionInvocationTarget::new_invocable_entity((*hash).into()),
737 );
738 session_entry_point = entry_point.clone();
739 session_args = args.clone();
740 }
741 ExecutableDeployItem::StoredContractByName {
742 name,
743 entry_point,
744 args,
745 } => {
746 session = ExecutableItem::Invocation(
747 TransactionInvocationTarget::new_invocable_entity_alias(name.clone()),
748 );
749 session_entry_point = entry_point.clone();
750 session_args = args.clone();
751 }
752 ExecutableDeployItem::StoredVersionedContractByHash {
753 hash,
754 version,
755 entry_point,
756 args,
757 } => {
758 session = ExecutableItem::Invocation(TransactionInvocationTarget::ByPackageHash {
759 addr: hash.value(),
760 version: *version,
761 protocol_version_major: None,
762 });
763 session_entry_point = entry_point.clone();
764 session_args = args.clone();
765 }
766 ExecutableDeployItem::StoredVersionedContractByName {
767 name,
768 version,
769 entry_point,
770 args,
771 } => {
772 session = ExecutableItem::Invocation(TransactionInvocationTarget::ByPackageName {
773 name: name.to_owned(),
774 version: *version,
775 protocol_version_major: None,
776 });
777 session_entry_point = entry_point.clone();
778 session_args = args.clone();
779 }
780 ExecutableDeployItem::Transfer { .. } => {
781 return Err(InvalidRequest::UnsupportedMode(
782 transaction_hash,
783 session_item.to_string(),
784 ));
785 }
786 }
787
788 Ok(SessionInfo(ExecutableInfo {
789 item: session,
790 entry_point: session_entry_point,
791 args: session_args,
792 }))
793}
794
795impl TryFrom<&SessionDataV1<'_>> for SessionInfo {
796 type Error = InvalidRequest;
797
798 fn try_from(v1_txn: &SessionDataV1) -> Result<Self, Self::Error> {
799 let transaction_hash = TransactionHash::V1(*v1_txn.hash());
800 let args = v1_txn.args().clone();
801 let session = match v1_txn.target() {
802 TransactionTarget::Native => {
803 return Err(InvalidRequest::InvalidTarget(
804 transaction_hash,
805 v1_txn.target().to_string(),
806 ));
807 }
808 TransactionTarget::Stored { id, .. } => {
809 let TransactionEntryPoint::Custom(entry_point) = v1_txn.entry_point() else {
810 return Err(InvalidRequest::InvalidEntryPoint(
811 transaction_hash,
812 v1_txn.entry_point().to_string(),
813 ));
814 };
815 let item = ExecutableItem::Invocation(id.clone());
816 ExecutableInfo {
817 item,
818 entry_point: entry_point.clone(),
819 args,
820 }
821 }
822 TransactionTarget::Session { module_bytes, .. } => {
823 if *v1_txn.entry_point() != TransactionEntryPoint::Call {
824 return Err(InvalidRequest::InvalidEntryPoint(
825 transaction_hash,
826 v1_txn.entry_point().to_string(),
827 ));
828 };
829 let kind = if v1_txn.is_install_upgrade() {
830 SessionKind::InstallUpgradeBytecode
831 } else {
832 SessionKind::GenericBytecode
833 };
834 let item = ExecutableItem::SessionBytes {
835 kind,
836 module_bytes: module_bytes.clone(),
837 };
838 ExecutableInfo {
839 item,
840 entry_point: DEFAULT_ENTRY_POINT.to_owned(),
841 args,
842 }
843 }
844 };
845
846 Ok(SessionInfo(session))
847 }
848}
849struct PaymentInfo(ExecutableInfo);
851
852impl Executable for PaymentInfo {
853 fn item(&self) -> ExecutableItem {
854 self.0.item.clone()
855 }
856
857 fn entry_point(&self) -> &String {
858 &self.0.entry_point
859 }
860
861 fn args(&self) -> &RuntimeArgs {
862 &self.0.args
863 }
864
865 fn phase(&self) -> Phase {
866 Phase::Payment
867 }
868}
869
870impl TryFrom<&SessionDataDeploy<'_>> for PaymentInfo {
871 type Error = InvalidRequest;
872
873 fn try_from(deploy_data: &SessionDataDeploy) -> Result<Self, Self::Error> {
874 let payment_item = deploy_data.session();
875 let transaction_hash = TransactionHash::Deploy(*deploy_data.deploy_hash());
876 build_payment_info_for_executable_item(payment_item, transaction_hash)
877 }
878}
879
880fn build_payment_info_for_executable_item(
881 payment_item: &ExecutableDeployItem,
882 transaction_hash: TransactionHash,
883) -> Result<PaymentInfo, InvalidRequest> {
884 match payment_item {
885 ExecutableDeployItem::ModuleBytes { module_bytes, args } => {
886 let payment = if module_bytes.is_empty() {
887 return Err(InvalidRequest::UnsupportedMode(
888 transaction_hash,
889 "standard payment is no longer handled by the execution engine".to_string(),
890 ));
891 } else {
892 ExecutableItem::PaymentBytes(module_bytes.clone())
893 };
894 Ok(PaymentInfo(ExecutableInfo {
895 item: payment,
896 entry_point: DEFAULT_ENTRY_POINT.to_string(),
897 args: args.clone(),
898 }))
899 }
900 ExecutableDeployItem::StoredContractByHash {
901 hash,
902 args,
903 entry_point,
904 } => Ok(PaymentInfo(ExecutableInfo {
905 item: ExecutableItem::Invocation(TransactionInvocationTarget::ByHash(hash.value())),
906 entry_point: entry_point.clone(),
907 args: args.clone(),
908 })),
909 ExecutableDeployItem::StoredContractByName {
910 name,
911 args,
912 entry_point,
913 } => Ok(PaymentInfo(ExecutableInfo {
914 item: ExecutableItem::Invocation(TransactionInvocationTarget::ByName(name.clone())),
915 entry_point: entry_point.clone(),
916 args: args.clone(),
917 })),
918 ExecutableDeployItem::StoredVersionedContractByHash {
919 args,
920 hash,
921 version,
922 entry_point,
923 } => Ok(PaymentInfo(ExecutableInfo {
924 item: ExecutableItem::Invocation(TransactionInvocationTarget::ByPackageHash {
925 addr: hash.value(),
926 version: *version,
927 protocol_version_major: None,
928 }),
929 entry_point: entry_point.clone(),
930 args: args.clone(),
931 })),
932 ExecutableDeployItem::StoredVersionedContractByName {
933 name,
934 version,
935 args,
936 entry_point,
937 } => Ok(PaymentInfo(ExecutableInfo {
938 item: ExecutableItem::Invocation(TransactionInvocationTarget::ByPackageName {
939 name: name.clone(),
940 version: *version,
941 protocol_version_major: None,
942 }),
943 entry_point: entry_point.clone(),
944 args: args.clone(),
945 })),
946 ExecutableDeployItem::Transfer { .. } => Err(InvalidRequest::UnexpectedVariant(
947 transaction_hash,
948 "payment item".to_string(),
949 )),
950 }
951}
952
953impl TryFrom<&SessionDataV1<'_>> for PaymentInfo {
954 type Error = InvalidRequest;
955
956 fn try_from(v1_txn: &SessionDataV1) -> Result<Self, Self::Error> {
957 let transaction_hash = TransactionHash::V1(*v1_txn.hash());
958 match v1_txn.pricing_mode() {
959 mode @ PricingMode::PaymentLimited {
960 standard_payment, ..
961 } => {
962 if *standard_payment {
963 return Err(InvalidRequest::UnsupportedMode(
964 transaction_hash,
965 mode.to_string(),
966 ));
967 }
968 }
969 mode @ PricingMode::Fixed { .. } | mode @ PricingMode::Prepaid { .. } => {
970 return Err(InvalidRequest::UnsupportedMode(
971 transaction_hash,
972 mode.to_string(),
973 ));
974 }
975 };
976
977 let payment = match v1_txn.target() {
978 TransactionTarget::Session { module_bytes, .. } => {
979 if *v1_txn.entry_point() != TransactionEntryPoint::Call {
980 return Err(InvalidRequest::InvalidEntryPoint(
981 transaction_hash,
982 v1_txn.entry_point().to_string(),
983 ));
984 };
985 let item = ExecutableItem::PaymentBytes(module_bytes.clone());
986 ExecutableInfo {
987 item,
988 entry_point: DEFAULT_ENTRY_POINT.to_owned(),
989 args: v1_txn.args().clone(),
990 }
991 }
992 TransactionTarget::Native | TransactionTarget::Stored { .. } => {
993 return Err(InvalidRequest::InvalidTarget(
994 transaction_hash,
995 v1_txn.target().to_string(),
996 ));
997 }
998 };
999
1000 Ok(PaymentInfo(payment))
1001 }
1002}