1#[cfg(any(feature = "testing", test, feature = "json-schema"))]
2pub(crate) mod arg_handling;
3mod errors_v1;
4pub mod fields_container;
5mod transaction_args;
6mod transaction_v1_hash;
7pub mod transaction_v1_payload;
8
9#[cfg(any(feature = "std", feature = "testing", test))]
10use super::InitiatorAddrAndSecretKey;
11use crate::{
12 bytesrepr::{self, Error, FromBytes, ToBytes},
13 crypto,
14};
15#[cfg(any(all(feature = "std", feature = "testing"), test))]
16use crate::{testing::TestRng, TransactionConfig, LARGE_WASM_LANE_ID};
17#[cfg(any(feature = "std", test))]
18use crate::{
19 TransactionEntryPoint, TransactionTarget, TransactionV1Config, AUCTION_LANE_ID,
20 INSTALL_UPGRADE_LANE_ID, MINT_LANE_ID,
21};
22#[cfg(any(feature = "std", test, feature = "testing"))]
23use alloc::collections::BTreeMap;
24use alloc::{collections::BTreeSet, vec::Vec};
25#[cfg(feature = "datasize")]
26use datasize::DataSize;
27use errors_v1::FieldDeserializationError;
28#[cfg(any(all(feature = "std", feature = "testing"), test))]
29use fields_container::FieldsContainer;
30#[cfg(any(all(feature = "std", feature = "testing"), test))]
31use fields_container::{ENTRY_POINT_MAP_KEY, TARGET_MAP_KEY};
32#[cfg(any(feature = "once_cell", test))]
33use once_cell::sync::OnceCell;
34#[cfg(any(all(feature = "std", feature = "testing"), test))]
35use rand::Rng;
36#[cfg(feature = "json-schema")]
37use schemars::JsonSchema;
38#[cfg(any(feature = "std", test))]
39use serde::{Deserialize, Serialize};
40#[cfg(any(feature = "std", test))]
41use thiserror::Error;
42use tracing::{error, trace};
43pub use transaction_v1_payload::TransactionV1Payload;
44#[cfg(any(feature = "std", test))]
45use transaction_v1_payload::TransactionV1PayloadJson;
46
47use super::{
48 serialization::{CalltableSerializationEnvelope, CalltableSerializationEnvelopeBuilder},
49 Approval, ApprovalsHash, InitiatorAddr, PricingMode,
50};
51#[cfg(any(feature = "std", feature = "testing", test))]
52use crate::bytesrepr::Bytes;
53use crate::{Digest, DisplayIter, SecretKey, TimeDiff, Timestamp};
54
55pub use errors_v1::{
56 DecodeFromJsonErrorV1 as TransactionV1DecodeFromJsonError, ErrorV1 as TransactionV1Error,
57 ExcessiveSizeErrorV1 as TransactionV1ExcessiveSizeError,
58 InvalidTransaction as InvalidTransactionV1,
59};
60pub use transaction_args::TransactionArgs;
61pub use transaction_v1_hash::TransactionV1Hash;
62
63use core::{
64 cmp,
65 fmt::{self, Debug, Display, Formatter},
66 hash,
67};
68
69const HASH_FIELD_INDEX: u16 = 0;
70const PAYLOAD_FIELD_INDEX: u16 = 1;
71const APPROVALS_FIELD_INDEX: u16 = 2;
72
73#[derive(Clone, Eq, Debug)]
76#[cfg_attr(any(feature = "std", test), derive(Serialize, Deserialize))]
77#[cfg_attr(feature = "datasize", derive(DataSize))]
78#[cfg_attr(
79 feature = "json-schema",
80 derive(JsonSchema),
81 schemars(with = "TransactionV1Json")
82)]
83pub struct TransactionV1 {
84 hash: TransactionV1Hash,
85 payload: TransactionV1Payload,
86 approvals: BTreeSet<Approval>,
87 #[cfg_attr(any(all(feature = "std", feature = "once_cell"), test), serde(skip))]
88 #[cfg_attr(
89 all(any(feature = "once_cell", test), feature = "datasize"),
90 data_size(skip)
91 )]
92 #[cfg(any(feature = "once_cell", test))]
93 is_verified: OnceCell<Result<(), InvalidTransactionV1>>,
94}
95
96#[cfg(any(feature = "std", test))]
97impl TryFrom<TransactionV1Json> for TransactionV1 {
98 type Error = TransactionV1JsonError;
99 fn try_from(transaction_v1_json: TransactionV1Json) -> Result<Self, Self::Error> {
100 Ok(TransactionV1 {
101 hash: transaction_v1_json.hash,
102 payload: transaction_v1_json.payload.try_into().map_err(|error| {
103 TransactionV1JsonError::FailedToMap(format!(
104 "Failed to map TransactionJson::V1 to Transaction::V1, err: {}",
105 error
106 ))
107 })?,
108 approvals: transaction_v1_json.approvals,
109 #[cfg(any(feature = "once_cell", test))]
110 is_verified: OnceCell::new(),
111 })
112 }
113}
114
115#[cfg(any(feature = "std", test))]
117#[derive(Clone, Serialize, Deserialize, PartialEq, Eq)]
118#[cfg_attr(
119 feature = "json-schema",
120 derive(JsonSchema),
121 schemars(
122 description = "A unit of work sent by a client to the network, which when executed can \
123 cause global state to be altered.",
124 rename = "TransactionV1",
125 )
126)]
127pub(super) struct TransactionV1Json {
128 hash: TransactionV1Hash,
129 payload: TransactionV1PayloadJson,
130 approvals: BTreeSet<Approval>,
131}
132
133#[cfg(any(feature = "std", test))]
134#[derive(Error, Debug)]
135pub(super) enum TransactionV1JsonError {
136 #[error("{0}")]
137 FailedToMap(String),
138}
139
140#[cfg(any(feature = "std", test))]
141impl TryFrom<TransactionV1> for TransactionV1Json {
142 type Error = TransactionV1JsonError;
143 fn try_from(transaction: TransactionV1) -> Result<Self, Self::Error> {
144 Ok(TransactionV1Json {
145 hash: transaction.hash,
146 payload: transaction.payload.try_into().map_err(|error| {
147 TransactionV1JsonError::FailedToMap(format!(
148 "Failed to map Transaction::V1 to TransactionJson::V1, err: {}",
149 error
150 ))
151 })?,
152 approvals: transaction.approvals,
153 })
154 }
155}
156
157impl TransactionV1 {
158 pub fn new(
160 hash: TransactionV1Hash,
161 payload: TransactionV1Payload,
162 approvals: BTreeSet<Approval>,
163 ) -> Self {
164 Self {
165 hash,
166 payload,
167 approvals,
168 #[cfg(any(feature = "once_cell", test))]
169 is_verified: OnceCell::new(),
170 }
171 }
172
173 #[cfg(any(feature = "std", test, feature = "testing"))]
174 pub(crate) fn build(
175 chain_name: String,
176 timestamp: Timestamp,
177 ttl: TimeDiff,
178 pricing_mode: PricingMode,
179 fields: BTreeMap<u16, Bytes>,
180 initiator_addr_and_secret_key: InitiatorAddrAndSecretKey,
181 ) -> TransactionV1 {
182 let initiator_addr = initiator_addr_and_secret_key.initiator_addr();
183 let transaction_v1_payload = TransactionV1Payload::new(
184 chain_name,
185 timestamp,
186 ttl,
187 pricing_mode,
188 initiator_addr,
189 fields,
190 );
191 let hash = Digest::hash(
192 transaction_v1_payload
193 .to_bytes()
194 .unwrap_or_else(|error| panic!("should serialize body: {}", error)),
195 );
196 let mut transaction =
197 TransactionV1::new(hash.into(), transaction_v1_payload, BTreeSet::new());
198
199 if let Some(secret_key) = initiator_addr_and_secret_key.secret_key() {
200 transaction.sign(secret_key);
201 }
202 transaction
203 }
204
205 pub fn sign(&mut self, secret_key: &SecretKey) {
207 let approval = Approval::create(&self.hash.into(), secret_key);
208 self.approvals.insert(approval);
209 }
210
211 pub fn hash(&self) -> &TransactionV1Hash {
213 &self.hash
214 }
215
216 pub fn payload(&self) -> &TransactionV1Payload {
218 &self.payload
219 }
220
221 pub fn approvals(&self) -> &BTreeSet<Approval> {
223 &self.approvals
224 }
225
226 pub fn initiator_addr(&self) -> &InitiatorAddr {
228 self.payload.initiator_addr()
229 }
230
231 pub fn chain_name(&self) -> &str {
233 self.payload.chain_name()
234 }
235
236 pub fn timestamp(&self) -> Timestamp {
238 self.payload.timestamp()
239 }
240
241 pub fn ttl(&self) -> TimeDiff {
245 self.payload.ttl()
246 }
247
248 pub fn expired(&self, current_instant: Timestamp) -> bool {
250 self.payload.expired(current_instant)
251 }
252
253 pub fn pricing_mode(&self) -> &PricingMode {
255 self.payload.pricing_mode()
256 }
257
258 pub fn compute_approvals_hash(&self) -> Result<ApprovalsHash, bytesrepr::Error> {
260 ApprovalsHash::compute(&self.approvals)
261 }
262
263 #[doc(hidden)]
264 pub fn with_approvals(mut self, approvals: BTreeSet<Approval>) -> Self {
265 self.approvals = approvals;
266 self
267 }
268
269 #[cfg(any(all(feature = "std", feature = "testing"), test))]
270 pub fn apply_approvals(&mut self, approvals: Vec<Approval>) {
271 self.approvals.extend(approvals);
272 }
273
274 #[cfg(any(all(feature = "std", feature = "testing"), test))]
276 pub fn payment_amount(&self) -> Option<u64> {
277 if let PricingMode::PaymentLimited { payment_amount, .. } = self.pricing_mode() {
278 Some(*payment_amount)
279 } else {
280 None
281 }
282 }
283
284 #[cfg(any(all(feature = "std", feature = "testing"), test))]
286 pub fn random(rng: &mut TestRng) -> Self {
287 let secret_key = SecretKey::random(rng);
288 let ttl_millis = rng.gen_range(60_000..TransactionConfig::default().max_ttl.millis());
289 let timestamp = Timestamp::random(rng);
290 let container = FieldsContainer::random(rng);
291 let initiator_addr_and_secret_key = InitiatorAddrAndSecretKey::SecretKey(&secret_key);
292 let pricing_mode = PricingMode::Fixed {
293 gas_price_tolerance: 5,
294 additional_computation_factor: 0,
295 };
296 TransactionV1::build(
297 rng.random_string(5..10),
298 timestamp,
299 TimeDiff::from_millis(ttl_millis),
300 pricing_mode,
301 container.to_map().unwrap(),
302 initiator_addr_and_secret_key,
303 )
304 }
305
306 #[cfg(any(all(feature = "std", feature = "testing"), test))]
307 pub fn random_with_lane_and_timestamp_and_ttl(
308 rng: &mut TestRng,
309 lane: u8,
310 maybe_timestamp: Option<Timestamp>,
311 ttl: Option<TimeDiff>,
312 ) -> Self {
313 let secret_key = SecretKey::random(rng);
314 let timestamp = maybe_timestamp.unwrap_or_else(Timestamp::now);
315 let ttl_millis = ttl.map_or(
316 rng.gen_range(60_000..TransactionConfig::default().max_ttl.millis()),
317 |ttl| ttl.millis(),
318 );
319 let container = FieldsContainer::random_of_lane(rng, lane);
320 let initiator_addr_and_secret_key = InitiatorAddrAndSecretKey::SecretKey(&secret_key);
321 let pricing_mode = PricingMode::Fixed {
322 gas_price_tolerance: 5,
323 additional_computation_factor: 0,
324 };
325 TransactionV1::build(
326 rng.random_string(5..10),
327 timestamp,
328 TimeDiff::from_millis(ttl_millis),
329 pricing_mode,
330 container.to_map().unwrap(),
331 initiator_addr_and_secret_key,
332 )
333 }
334
335 #[cfg(any(all(feature = "std", feature = "testing"), test))]
336 pub fn random_with_timestamp_and_ttl(
337 rng: &mut TestRng,
338 maybe_timestamp: Option<Timestamp>,
339 ttl: Option<TimeDiff>,
340 ) -> Self {
341 Self::random_with_lane_and_timestamp_and_ttl(
342 rng,
343 INSTALL_UPGRADE_LANE_ID,
344 maybe_timestamp,
345 ttl,
346 )
347 }
348
349 #[cfg(any(all(feature = "std", feature = "testing"), test))]
351 pub fn random_transfer(
352 rng: &mut TestRng,
353 timestamp: Option<Timestamp>,
354 ttl: Option<TimeDiff>,
355 ) -> Self {
356 TransactionV1::random_with_lane_and_timestamp_and_ttl(rng, MINT_LANE_ID, timestamp, ttl)
357 }
358
359 #[cfg(any(all(feature = "std", feature = "testing"), test))]
361 pub fn random_wasm(
362 rng: &mut TestRng,
363 timestamp: Option<Timestamp>,
364 ttl: Option<TimeDiff>,
365 ) -> Self {
366 TransactionV1::random_with_lane_and_timestamp_and_ttl(
367 rng,
368 LARGE_WASM_LANE_ID,
369 timestamp,
370 ttl,
371 )
372 }
373
374 #[cfg(any(all(feature = "std", feature = "testing"), test))]
376 pub fn random_auction(
377 rng: &mut TestRng,
378 timestamp: Option<Timestamp>,
379 ttl: Option<TimeDiff>,
380 ) -> Self {
381 TransactionV1::random_with_lane_and_timestamp_and_ttl(rng, AUCTION_LANE_ID, timestamp, ttl)
382 }
383
384 #[cfg(any(all(feature = "std", feature = "testing"), test))]
386 pub fn random_install_upgrade(
387 rng: &mut TestRng,
388 timestamp: Option<Timestamp>,
389 ttl: Option<TimeDiff>,
390 ) -> Self {
391 TransactionV1::random_with_lane_and_timestamp_and_ttl(
392 rng,
393 INSTALL_UPGRADE_LANE_ID,
394 timestamp,
395 ttl,
396 )
397 }
398
399 pub fn deserialize_field<T: FromBytes>(
401 &self,
402 index: u16,
403 ) -> Result<T, FieldDeserializationError> {
404 self.payload.deserialize_field(index)
405 }
406
407 pub fn number_of_fields(&self) -> usize {
409 self.payload.number_of_fields()
410 }
411
412 pub fn has_valid_hash(&self) -> Result<(), InvalidTransactionV1> {
414 let computed_hash = Digest::hash(self.payload.to_bytes().map_err(|error| {
415 error!(
416 ?error,
417 "Could not serialize transaction for purpose of calculating hash."
418 );
419 InvalidTransactionV1::CouldNotSerializeTransaction
420 })?);
421 if TransactionV1Hash::new(computed_hash) != self.hash {
422 trace!(?self, ?computed_hash, "invalid transaction hash");
423 return Err(InvalidTransactionV1::InvalidTransactionHash);
424 }
425 Ok(())
426 }
427
428 pub fn verify(&self) -> Result<(), InvalidTransactionV1> {
433 #[cfg(any(feature = "once_cell", test))]
434 return self.is_verified.get_or_init(|| self.do_verify()).clone();
435
436 #[cfg(not(any(feature = "once_cell", test)))]
437 self.do_verify()
438 }
439
440 fn do_verify(&self) -> Result<(), InvalidTransactionV1> {
441 if self.approvals.is_empty() {
442 trace!(?self, "transaction has no approvals");
443 return Err(InvalidTransactionV1::EmptyApprovals);
444 }
445
446 self.has_valid_hash()?;
447
448 for (index, approval) in self.approvals.iter().enumerate() {
449 if let Err(error) = crypto::verify(self.hash, approval.signature(), approval.signer()) {
450 trace!(
451 ?self,
452 "failed to verify transaction approval {}: {}",
453 index,
454 error
455 );
456 return Err(InvalidTransactionV1::InvalidApproval { index, error });
457 }
458 }
459
460 Ok(())
461 }
462
463 pub fn payload_hash(&self) -> Result<Digest, InvalidTransactionV1> {
465 let bytes = self
466 .payload
467 .fields()
468 .to_bytes()
469 .map_err(|_| InvalidTransactionV1::CannotCalculateFieldsHash)?;
470 Ok(Digest::hash(bytes))
471 }
472
473 fn serialized_field_lengths(&self) -> Vec<usize> {
474 vec![
475 self.hash.serialized_length(),
476 self.payload.serialized_length(),
477 self.approvals.serialized_length(),
478 ]
479 }
480
481 #[cfg(any(all(feature = "std", feature = "testing"), test))]
484 pub fn invalidate(&mut self) {
485 self.payload.invalidate();
486 }
487
488 #[cfg(any(all(feature = "std", feature = "testing"), test))]
489 pub(crate) fn get_transaction_target(&self) -> Result<TransactionTarget, InvalidTransactionV1> {
490 self.deserialize_field::<TransactionTarget>(TARGET_MAP_KEY)
491 .map_err(|error| InvalidTransactionV1::CouldNotDeserializeField { error })
492 }
493
494 #[cfg(any(all(feature = "std", feature = "testing"), test))]
495 pub(crate) fn get_transaction_entry_point(
496 &self,
497 ) -> Result<TransactionEntryPoint, InvalidTransactionV1> {
498 self.deserialize_field::<TransactionEntryPoint>(ENTRY_POINT_MAP_KEY)
499 .map_err(|error| InvalidTransactionV1::CouldNotDeserializeField { error })
500 }
501
502 pub fn gas_price_tolerance(&self) -> u8 {
504 match self.pricing_mode() {
505 PricingMode::PaymentLimited {
506 gas_price_tolerance,
507 ..
508 } => *gas_price_tolerance,
509 PricingMode::Fixed {
510 gas_price_tolerance,
511 ..
512 } => *gas_price_tolerance,
513 PricingMode::Prepaid { .. } => {
514 0u8
516 }
517 }
518 }
519}
520
521impl ToBytes for TransactionV1 {
522 fn to_bytes(&self) -> Result<Vec<u8>, crate::bytesrepr::Error> {
523 let expected_payload_sizes = self.serialized_field_lengths();
524 CalltableSerializationEnvelopeBuilder::new(expected_payload_sizes)?
525 .add_field(HASH_FIELD_INDEX, &self.hash)?
526 .add_field(PAYLOAD_FIELD_INDEX, &self.payload)?
527 .add_field(APPROVALS_FIELD_INDEX, &self.approvals)?
528 .binary_payload_bytes()
529 }
530
531 fn serialized_length(&self) -> usize {
532 CalltableSerializationEnvelope::estimate_size(self.serialized_field_lengths())
533 }
534}
535
536impl FromBytes for TransactionV1 {
537 fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), Error> {
538 let (binary_payload, remainder) = CalltableSerializationEnvelope::from_bytes(3, bytes)?;
539 let window = binary_payload.start_consuming()?.ok_or(Error::Formatting)?;
540 window.verify_index(HASH_FIELD_INDEX)?;
541 let (hash, window) = window.deserialize_and_maybe_next::<TransactionV1Hash>()?;
542 let window = window.ok_or(Error::Formatting)?;
543 window.verify_index(PAYLOAD_FIELD_INDEX)?;
544 let (payload, window) = window.deserialize_and_maybe_next::<TransactionV1Payload>()?;
545 let window = window.ok_or(Error::Formatting)?;
546 window.verify_index(APPROVALS_FIELD_INDEX)?;
547 let (approvals, window) = window.deserialize_and_maybe_next::<BTreeSet<Approval>>()?;
548 if window.is_some() {
549 return Err(Error::Formatting);
550 }
551 let from_bytes = TransactionV1 {
552 hash,
553 payload,
554 approvals,
555 #[cfg(any(feature = "once_cell", test))]
556 is_verified: OnceCell::new(),
557 };
558 Ok((from_bytes, remainder))
559 }
560}
561
562impl Display for TransactionV1 {
563 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
564 write!(
565 formatter,
566 "transaction-v1[{}, {}, approvals: {}]",
567 self.hash,
568 self.payload,
569 DisplayIter::new(self.approvals.iter())
570 )
571 }
572}
573
574impl hash::Hash for TransactionV1 {
575 fn hash<H: hash::Hasher>(&self, state: &mut H) {
576 let TransactionV1 {
578 hash,
579 payload,
580 approvals,
581 #[cfg(any(feature = "once_cell", test))]
582 is_verified: _,
583 } = self;
584 hash.hash(state);
585 payload.hash(state);
586 approvals.hash(state);
587 }
588}
589
590impl PartialEq for TransactionV1 {
591 fn eq(&self, other: &TransactionV1) -> bool {
592 let TransactionV1 {
594 hash,
595 payload,
596 approvals,
597 #[cfg(any(feature = "once_cell", test))]
598 is_verified: _,
599 } = self;
600 *hash == other.hash && *payload == other.payload && *approvals == other.approvals
601 }
602}
603
604impl Ord for TransactionV1 {
605 fn cmp(&self, other: &TransactionV1) -> cmp::Ordering {
606 let TransactionV1 {
608 hash,
609 payload,
610 approvals,
611 #[cfg(any(feature = "once_cell", test))]
612 is_verified: _,
613 } = self;
614 hash.cmp(&other.hash)
615 .then_with(|| payload.cmp(&other.payload))
616 .then_with(|| approvals.cmp(&other.approvals))
617 }
618}
619
620impl PartialOrd for TransactionV1 {
621 fn partial_cmp(&self, other: &TransactionV1) -> Option<cmp::Ordering> {
622 Some(self.cmp(other))
623 }
624}
625
626#[cfg(any(feature = "std", test))]
627pub fn calculate_transaction_lane(
629 entry_point: &TransactionEntryPoint,
630 target: &TransactionTarget,
631 pricing_mode: &PricingMode,
632 config: &TransactionV1Config,
633 size_estimation: u64,
634 runtime_args_size: u64,
635) -> Result<u8, InvalidTransactionV1> {
636 use crate::TransactionRuntimeParams;
637
638 use super::get_lane_for_non_install_wasm;
639
640 match target {
641 TransactionTarget::Native => match entry_point {
642 TransactionEntryPoint::Transfer | TransactionEntryPoint::Burn => Ok(MINT_LANE_ID),
643 TransactionEntryPoint::AddBid
644 | TransactionEntryPoint::WithdrawBid
645 | TransactionEntryPoint::Delegate
646 | TransactionEntryPoint::Undelegate
647 | TransactionEntryPoint::Redelegate
648 | TransactionEntryPoint::ActivateBid
649 | TransactionEntryPoint::ChangeBidPublicKey
650 | TransactionEntryPoint::AddReservations
651 | TransactionEntryPoint::CancelReservations => Ok(AUCTION_LANE_ID),
652 TransactionEntryPoint::Call => Err(InvalidTransactionV1::EntryPointCannotBeCall),
653 TransactionEntryPoint::Custom(_) => {
654 Err(InvalidTransactionV1::EntryPointCannotBeCustom {
655 entry_point: entry_point.clone(),
656 })
657 }
658 },
659 TransactionTarget::Stored { .. } => match entry_point {
660 TransactionEntryPoint::Custom(_) => get_lane_for_non_install_wasm(
661 config,
662 pricing_mode,
663 size_estimation,
664 runtime_args_size,
665 )
666 .map_err(Into::into),
667 TransactionEntryPoint::Call
668 | TransactionEntryPoint::Transfer
669 | TransactionEntryPoint::Burn
670 | TransactionEntryPoint::AddBid
671 | TransactionEntryPoint::WithdrawBid
672 | TransactionEntryPoint::Delegate
673 | TransactionEntryPoint::Undelegate
674 | TransactionEntryPoint::Redelegate
675 | TransactionEntryPoint::ActivateBid
676 | TransactionEntryPoint::ChangeBidPublicKey
677 | TransactionEntryPoint::AddReservations
678 | TransactionEntryPoint::CancelReservations => {
679 Err(InvalidTransactionV1::EntryPointMustBeCustom {
680 entry_point: entry_point.clone(),
681 })
682 }
683 },
684 TransactionTarget::Session {
685 is_install_upgrade,
686 runtime: TransactionRuntimeParams::VmCasperV1,
687 ..
688 } => match entry_point {
689 TransactionEntryPoint::Call => {
690 if *is_install_upgrade {
691 Ok(INSTALL_UPGRADE_LANE_ID)
692 } else {
693 get_lane_for_non_install_wasm(
694 config,
695 pricing_mode,
696 size_estimation,
697 runtime_args_size,
698 )
699 .map_err(Into::into)
700 }
701 }
702 TransactionEntryPoint::Custom(_)
703 | TransactionEntryPoint::Transfer
704 | TransactionEntryPoint::Burn
705 | TransactionEntryPoint::AddBid
706 | TransactionEntryPoint::WithdrawBid
707 | TransactionEntryPoint::Delegate
708 | TransactionEntryPoint::Undelegate
709 | TransactionEntryPoint::Redelegate
710 | TransactionEntryPoint::ActivateBid
711 | TransactionEntryPoint::ChangeBidPublicKey
712 | TransactionEntryPoint::AddReservations
713 | TransactionEntryPoint::CancelReservations => {
714 Err(InvalidTransactionV1::EntryPointMustBeCall {
715 entry_point: entry_point.clone(),
716 })
717 }
718 },
719 TransactionTarget::Session {
720 is_install_upgrade,
721 runtime: TransactionRuntimeParams::VmCasperV2 { .. },
722 ..
723 } => match entry_point {
724 TransactionEntryPoint::Call | TransactionEntryPoint::Custom(_) => {
725 if *is_install_upgrade {
726 Ok(INSTALL_UPGRADE_LANE_ID)
727 } else {
728 get_lane_for_non_install_wasm(
729 config,
730 pricing_mode,
731 size_estimation,
732 runtime_args_size,
733 )
734 .map_err(Into::into)
735 }
736 }
737 TransactionEntryPoint::Transfer
738 | TransactionEntryPoint::Burn
739 | TransactionEntryPoint::AddBid
740 | TransactionEntryPoint::WithdrawBid
741 | TransactionEntryPoint::Delegate
742 | TransactionEntryPoint::Undelegate
743 | TransactionEntryPoint::Redelegate
744 | TransactionEntryPoint::ActivateBid
745 | TransactionEntryPoint::ChangeBidPublicKey
746 | TransactionEntryPoint::AddReservations
747 | TransactionEntryPoint::CancelReservations => {
748 Err(InvalidTransactionV1::EntryPointMustBeCall {
749 entry_point: entry_point.clone(),
750 })
751 }
752 },
753 }
754}