casper_types/transaction/
transaction_v1.rs

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/// A unit of work sent by a client to the network, which when executed can cause global state to
74/// be altered.
75#[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/// A helper struct to represent the transaction as json.
116#[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    /// ctor
159    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    /// Adds a signature of this transaction's hash to its approvals.
206    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    /// Returns the `ApprovalsHash` of this transaction's approvals.
212    pub fn hash(&self) -> &TransactionV1Hash {
213        &self.hash
214    }
215
216    /// Returns the internal payload of this transaction.
217    pub fn payload(&self) -> &TransactionV1Payload {
218        &self.payload
219    }
220
221    /// Returns transactions approvals.
222    pub fn approvals(&self) -> &BTreeSet<Approval> {
223        &self.approvals
224    }
225
226    /// Returns the address of the initiator of the transaction.
227    pub fn initiator_addr(&self) -> &InitiatorAddr {
228        self.payload.initiator_addr()
229    }
230
231    /// Returns the name of the chain the transaction should be executed on.
232    pub fn chain_name(&self) -> &str {
233        self.payload.chain_name()
234    }
235
236    /// Returns the creation timestamp of the transaction.
237    pub fn timestamp(&self) -> Timestamp {
238        self.payload.timestamp()
239    }
240
241    /// Returns the duration after the creation timestamp for which the transaction will stay valid.
242    ///
243    /// After this duration has ended, the transaction will be considered expired.
244    pub fn ttl(&self) -> TimeDiff {
245        self.payload.ttl()
246    }
247
248    /// Returns `true` if the transaction has expired.
249    pub fn expired(&self, current_instant: Timestamp) -> bool {
250        self.payload.expired(current_instant)
251    }
252
253    /// Returns the pricing mode for the transaction.
254    pub fn pricing_mode(&self) -> &PricingMode {
255        self.payload.pricing_mode()
256    }
257
258    /// Returns the `ApprovalsHash` of this transaction's approvals.
259    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    /// Returns the payment amount if the txn is using payment limited mode.
275    #[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    /// Returns a random, valid but possibly expired transaction.
285    #[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    /// Returns a random transaction with "transfer" category.
350    #[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    /// Returns a random transaction with "standard" category.
360    #[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    /// Returns a random transaction with "install/upgrade" category.
375    #[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    /// Returns a random transaction with "install/upgrade" category.
385    #[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    /// Returns result of attempting to deserailize a field from the amorphic `fields` container.
400    pub fn deserialize_field<T: FromBytes>(
401        &self,
402        index: u16,
403    ) -> Result<T, FieldDeserializationError> {
404        self.payload.deserialize_field(index)
405    }
406
407    /// Returns number of fields in the amorphic `fields` container.
408    pub fn number_of_fields(&self) -> usize {
409        self.payload.number_of_fields()
410    }
411
412    /// Checks if the declared hash of the transaction matches calculated hash.
413    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    /// Returns `Ok` if and only if:
429    ///   * the transaction hash is correct (see [`TransactionV1::has_valid_hash`] for details)
430    ///   * approvals are non-empty, and
431    ///   * all approvals are valid signatures of the signed hash
432    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    /// Returns the hash of the transaction's payload.
464    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    /// Turns `self` into an invalid `TransactionV1` by clearing the `chain_name`, invalidating the
482    /// transaction hash
483    #[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    /// Returns the gas price tolerance for the given transaction.
503    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                // TODO: Change this when reserve gets implemented.
515                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        // Destructure to make sure we don't accidentally omit fields.
577        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        // Destructure to make sure we don't accidentally omit fields.
593        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        // Destructure to make sure we don't accidentally omit fields.
607        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))]
627/// Calculates the laned based on properties of the transaction
628pub 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}