iota_types/
transaction.rs

1// Copyright (c) 2021, Facebook, Inc. and its affiliates
2// Copyright (c) Mysten Labs, Inc.
3// Modifications Copyright (c) 2024 IOTA Stiftung
4// SPDX-License-Identifier: Apache-2.0
5
6use std::{
7    collections::{BTreeMap, BTreeSet, HashSet},
8    fmt::{Debug, Display, Formatter, Write},
9    hash::Hash,
10    iter,
11    iter::once,
12    sync::Arc,
13};
14
15use anyhow::bail;
16use enum_dispatch::enum_dispatch;
17use fastcrypto::{encoding::Base64, hash::HashFunction};
18use iota_protocol_config::ProtocolConfig;
19use itertools::Either;
20use move_core_types::{
21    ident_str,
22    identifier::{IdentStr, Identifier},
23    language_storage::TypeTag,
24};
25use nonempty::{NonEmpty, nonempty};
26use serde::{Deserialize, Serialize};
27use shared_crypto::intent::{Intent, IntentMessage, IntentScope};
28use strum::IntoStaticStr;
29use tap::Pipe;
30use tracing::trace;
31
32use super::{base_types::*, error::*};
33use crate::{
34    IOTA_AUTHENTICATOR_STATE_OBJECT_ID, IOTA_AUTHENTICATOR_STATE_OBJECT_SHARED_VERSION,
35    IOTA_CLOCK_OBJECT_ID, IOTA_CLOCK_OBJECT_SHARED_VERSION, IOTA_FRAMEWORK_PACKAGE_ID,
36    IOTA_RANDOMNESS_STATE_OBJECT_ID, IOTA_SYSTEM_STATE_OBJECT_ID,
37    IOTA_SYSTEM_STATE_OBJECT_SHARED_VERSION,
38    authenticator_state::ActiveJwk,
39    committee::{Committee, EpochId, ProtocolVersion},
40    crypto::{
41        AuthoritySignInfo, AuthoritySignInfoTrait, AuthoritySignature,
42        AuthorityStrongQuorumSignInfo, DefaultHash, Ed25519IotaSignature, EmptySignInfo,
43        IotaSignatureInner, RandomnessRound, Signature, Signer, ToFromBytes, default_hash,
44    },
45    digests::{
46        CertificateDigest, ConsensusCommitDigest, SenderSignedDataDigest, ZKLoginInputsDigest,
47    },
48    event::Event,
49    execution::SharedInput,
50    message_envelope::{Envelope, Message, TrustedEnvelope, VerifiedEnvelope},
51    messages_checkpoint::CheckpointTimestamp,
52    messages_consensus::{ConsensusCommitPrologueV1, ConsensusDeterminedVersionAssignments},
53    object::{MoveObject, Object, Owner},
54    programmable_transaction_builder::ProgrammableTransactionBuilder,
55    signature::{GenericSignature, VerifyParams},
56    signature_verification::{VerifiedDigestCache, verify_sender_signed_data_message_signatures},
57};
58
59pub const TEST_ONLY_GAS_UNIT_FOR_TRANSFER: u64 = 10_000;
60pub const TEST_ONLY_GAS_UNIT_FOR_OBJECT_BASICS: u64 = 50_000;
61pub const TEST_ONLY_GAS_UNIT_FOR_PUBLISH: u64 = 50_000;
62pub const TEST_ONLY_GAS_UNIT_FOR_STAKING: u64 = 50_000;
63pub const TEST_ONLY_GAS_UNIT_FOR_GENERIC: u64 = 50_000;
64pub const TEST_ONLY_GAS_UNIT_FOR_SPLIT_COIN: u64 = 10_000;
65// For some transactions we may either perform heavy operations or touch
66// objects that are storage expensive. That may happen (and often is the case)
67// because the object touched are set up in genesis and carry no storage cost
68// (and thus rebate) on first usage.
69pub const TEST_ONLY_GAS_UNIT_FOR_HEAVY_COMPUTATION_STORAGE: u64 = 5_000_000;
70
71pub const GAS_PRICE_FOR_SYSTEM_TX: u64 = 1;
72
73pub const DEFAULT_VALIDATOR_GAS_PRICE: u64 = 1000;
74
75const BLOCKED_MOVE_FUNCTIONS: [(ObjectID, &str, &str); 0] = [];
76
77#[cfg(test)]
78#[path = "unit_tests/messages_tests.rs"]
79mod messages_tests;
80
81#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
82pub enum CallArg {
83    // contains no structs or objects
84    Pure(Vec<u8>),
85    // an object
86    Object(ObjectArg),
87}
88
89impl CallArg {
90    pub const IOTA_SYSTEM_MUT: Self = Self::Object(ObjectArg::IOTA_SYSTEM_MUT);
91    pub const CLOCK_IMM: Self = Self::Object(ObjectArg::SharedObject {
92        id: IOTA_CLOCK_OBJECT_ID,
93        initial_shared_version: IOTA_CLOCK_OBJECT_SHARED_VERSION,
94        mutable: false,
95    });
96    pub const CLOCK_MUT: Self = Self::Object(ObjectArg::SharedObject {
97        id: IOTA_CLOCK_OBJECT_ID,
98        initial_shared_version: IOTA_CLOCK_OBJECT_SHARED_VERSION,
99        mutable: true,
100    });
101    pub const AUTHENTICATOR_MUT: Self = Self::Object(ObjectArg::SharedObject {
102        id: IOTA_AUTHENTICATOR_STATE_OBJECT_ID,
103        initial_shared_version: IOTA_AUTHENTICATOR_STATE_OBJECT_SHARED_VERSION,
104        mutable: true,
105    });
106}
107
108#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, Serialize, Deserialize)]
109pub enum ObjectArg {
110    // A Move object, either immutable, or owned mutable.
111    ImmOrOwnedObject(ObjectRef),
112    // A Move object that's shared.
113    // SharedObject::mutable controls whether caller asks for a mutable reference to shared
114    // object.
115    SharedObject {
116        id: ObjectID,
117        initial_shared_version: SequenceNumber,
118        mutable: bool,
119    },
120    // A Move object that can be received in this transaction.
121    Receiving(ObjectRef),
122}
123
124fn type_tag_validity_check(
125    tag: &TypeTag,
126    config: &ProtocolConfig,
127    starting_count: &mut usize,
128) -> UserInputResult<()> {
129    let mut stack = vec![(tag, 1)];
130    while let Some((tag, depth)) = stack.pop() {
131        *starting_count += 1;
132        fp_ensure!(
133            *starting_count < config.max_type_arguments() as usize,
134            UserInputError::SizeLimitExceeded {
135                limit: "maximum type arguments in a call transaction".to_string(),
136                value: config.max_type_arguments().to_string()
137            }
138        );
139        fp_ensure!(
140            depth < config.max_type_argument_depth(),
141            UserInputError::SizeLimitExceeded {
142                limit: "maximum type argument depth in a call transaction".to_string(),
143                value: config.max_type_argument_depth().to_string()
144            }
145        );
146        match tag {
147            TypeTag::Bool
148            | TypeTag::U8
149            | TypeTag::U64
150            | TypeTag::U128
151            | TypeTag::Address
152            | TypeTag::Signer
153            | TypeTag::U16
154            | TypeTag::U32
155            | TypeTag::U256 => (),
156            TypeTag::Vector(t) => {
157                stack.push((t, depth + 1));
158            }
159            TypeTag::Struct(s) => {
160                let next_depth = depth + 1;
161                stack.extend(s.type_params.iter().map(|t| (t, next_depth)));
162            }
163        }
164    }
165    Ok(())
166}
167
168// System transaction for advancing the epoch.
169#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
170pub struct ChangeEpoch {
171    /// The next (to become) epoch ID.
172    pub epoch: EpochId,
173    /// The protocol version in effect in the new epoch.
174    pub protocol_version: ProtocolVersion,
175    /// The total amount of gas charged for storage during the epoch.
176    pub storage_charge: u64,
177    /// The total amount of gas charged for computation during the epoch.
178    pub computation_charge: u64,
179    /// The amount of storage rebate refunded to the txn senders.
180    pub storage_rebate: u64,
181    /// The non-refundable storage fee.
182    pub non_refundable_storage_fee: u64,
183    /// Unix timestamp when epoch started
184    pub epoch_start_timestamp_ms: u64,
185    /// System packages (specifically framework and move stdlib) that are
186    /// written before the new epoch starts. This tracks framework upgrades
187    /// on chain. When executing the ChangeEpoch txn, the validator must
188    /// write out the modules below.  Modules are provided with the version they
189    /// will be upgraded to, their modules in serialized form (which include
190    /// their package ID), and a list of their transitive dependencies.
191    pub system_packages: Vec<(SequenceNumber, Vec<Vec<u8>>, Vec<ObjectID>)>,
192}
193
194// System transaction for advancing the epoch.
195// This version includes the computation_charge_burned field for when
196// protocol_defined_base_fee is enabled in the protocol config.
197#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
198pub struct ChangeEpochV2 {
199    /// The next (to become) epoch ID.
200    pub epoch: EpochId,
201    /// The protocol version in effect in the new epoch.
202    pub protocol_version: ProtocolVersion,
203    /// The total amount of gas charged for storage during the epoch.
204    pub storage_charge: u64,
205    /// The total amount of gas charged for computation during the epoch.
206    pub computation_charge: u64,
207    /// The burned component of the total computation/execution costs.
208    pub computation_charge_burned: u64,
209    /// The amount of storage rebate refunded to the txn senders.
210    pub storage_rebate: u64,
211    /// The non-refundable storage fee.
212    pub non_refundable_storage_fee: u64,
213    /// Unix timestamp when epoch started
214    pub epoch_start_timestamp_ms: u64,
215    /// System packages (specifically framework and move stdlib) that are
216    /// written before the new epoch starts. This tracks framework upgrades
217    /// on chain. When executing the ChangeEpochV2 txn, the validator must
218    /// write out the modules below.  Modules are provided with the version they
219    /// will be upgraded to, their modules in serialized form (which include
220    /// their package ID), and a list of their transitive dependencies.
221    pub system_packages: Vec<(SequenceNumber, Vec<Vec<u8>>, Vec<ObjectID>)>,
222}
223
224#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
225pub struct GenesisTransaction {
226    pub objects: Vec<GenesisObject>,
227    pub events: Vec<Event>,
228}
229
230#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
231pub enum GenesisObject {
232    RawObject {
233        data: crate::object::Data,
234        owner: crate::object::Owner,
235    },
236}
237
238impl GenesisObject {
239    pub fn id(&self) -> ObjectID {
240        match self {
241            GenesisObject::RawObject { data, .. } => data.id(),
242        }
243    }
244}
245
246#[derive(Debug, Hash, PartialEq, Eq, Clone, Serialize, Deserialize)]
247pub struct AuthenticatorStateExpire {
248    /// expire JWKs that have a lower epoch than this
249    pub min_epoch: u64,
250    /// The initial version of the authenticator object that it was shared at.
251    pub authenticator_obj_initial_shared_version: SequenceNumber,
252}
253
254impl AuthenticatorStateExpire {
255    pub fn authenticator_obj_initial_shared_version(&self) -> SequenceNumber {
256        self.authenticator_obj_initial_shared_version
257    }
258}
259
260#[derive(Debug, Hash, PartialEq, Eq, Clone, Serialize, Deserialize)]
261pub struct AuthenticatorStateUpdateV1 {
262    /// Epoch of the authenticator state update transaction
263    pub epoch: u64,
264    /// Consensus round of the authenticator state update
265    pub round: u64,
266    /// newly active jwks
267    pub new_active_jwks: Vec<ActiveJwk>,
268    /// The initial version of the authenticator object that it was shared at.
269    pub authenticator_obj_initial_shared_version: SequenceNumber,
270    // to version this struct, do not add new fields. Instead, add a AuthenticatorStateUpdateV2 to
271    // TransactionKind.
272}
273
274impl AuthenticatorStateUpdateV1 {
275    pub fn authenticator_obj_initial_shared_version(&self) -> SequenceNumber {
276        self.authenticator_obj_initial_shared_version
277    }
278}
279
280#[derive(Debug, Hash, PartialEq, Eq, Clone, Serialize, Deserialize)]
281pub struct RandomnessStateUpdate {
282    /// Epoch of the randomness state update transaction
283    pub epoch: u64,
284    /// Randomness round of the update
285    pub randomness_round: RandomnessRound,
286    /// Updated random bytes
287    pub random_bytes: Vec<u8>,
288    /// The initial version of the randomness object that it was shared at.
289    pub randomness_obj_initial_shared_version: SequenceNumber,
290    // to version this struct, do not add new fields. Instead, add a RandomnessStateUpdateV2 to
291    // TransactionKind.
292}
293
294impl RandomnessStateUpdate {
295    pub fn randomness_obj_initial_shared_version(&self) -> SequenceNumber {
296        self.randomness_obj_initial_shared_version
297    }
298}
299
300#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, IntoStaticStr)]
301pub enum TransactionKind {
302    /// A transaction that allows the interleaving of native commands and Move
303    /// calls
304    ProgrammableTransaction(ProgrammableTransaction),
305    /// A system transaction that will update epoch information on-chain.
306    /// It will only ever be executed once in an epoch.
307    /// The argument is the next epoch number, which is critical
308    /// because it ensures that this transaction has a unique digest.
309    /// This will eventually be translated to a Move call during execution.
310    /// It also doesn't require/use a gas object.
311    /// A validator will not sign a transaction of this kind from outside. It
312    /// only signs internally during epoch changes.
313    Genesis(GenesisTransaction),
314    ConsensusCommitPrologueV1(ConsensusCommitPrologueV1),
315    AuthenticatorStateUpdateV1(AuthenticatorStateUpdateV1),
316
317    /// EndOfEpochTransaction contains a list of transactions
318    /// that are allowed to run at the end of the epoch.
319    EndOfEpochTransaction(Vec<EndOfEpochTransactionKind>),
320
321    RandomnessStateUpdate(RandomnessStateUpdate),
322    // .. more transaction types go here
323}
324
325/// EndOfEpochTransactionKind
326#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, IntoStaticStr)]
327pub enum EndOfEpochTransactionKind {
328    ChangeEpoch(ChangeEpoch),
329    ChangeEpochV2(ChangeEpochV2),
330    AuthenticatorStateCreate,
331    AuthenticatorStateExpire(AuthenticatorStateExpire),
332}
333
334impl EndOfEpochTransactionKind {
335    pub fn new_change_epoch(
336        next_epoch: EpochId,
337        protocol_version: ProtocolVersion,
338        storage_charge: u64,
339        computation_charge: u64,
340        storage_rebate: u64,
341        non_refundable_storage_fee: u64,
342        epoch_start_timestamp_ms: u64,
343        system_packages: Vec<(SequenceNumber, Vec<Vec<u8>>, Vec<ObjectID>)>,
344    ) -> Self {
345        Self::ChangeEpoch(ChangeEpoch {
346            epoch: next_epoch,
347            protocol_version,
348            storage_charge,
349            computation_charge,
350            storage_rebate,
351            non_refundable_storage_fee,
352            epoch_start_timestamp_ms,
353            system_packages,
354        })
355    }
356
357    pub fn new_change_epoch_v2(
358        next_epoch: EpochId,
359        protocol_version: ProtocolVersion,
360        storage_charge: u64,
361        computation_charge: u64,
362        computation_charge_burned: u64,
363        storage_rebate: u64,
364        non_refundable_storage_fee: u64,
365        epoch_start_timestamp_ms: u64,
366        system_packages: Vec<(SequenceNumber, Vec<Vec<u8>>, Vec<ObjectID>)>,
367    ) -> Self {
368        Self::ChangeEpochV2(ChangeEpochV2 {
369            epoch: next_epoch,
370            protocol_version,
371            storage_charge,
372            computation_charge,
373            computation_charge_burned,
374            storage_rebate,
375            non_refundable_storage_fee,
376            epoch_start_timestamp_ms,
377            system_packages,
378        })
379    }
380
381    pub fn new_authenticator_state_expire(
382        min_epoch: u64,
383        authenticator_obj_initial_shared_version: SequenceNumber,
384    ) -> Self {
385        Self::AuthenticatorStateExpire(AuthenticatorStateExpire {
386            min_epoch,
387            authenticator_obj_initial_shared_version,
388        })
389    }
390
391    pub fn new_authenticator_state_create() -> Self {
392        Self::AuthenticatorStateCreate
393    }
394
395    fn input_objects(&self) -> Vec<InputObjectKind> {
396        match self {
397            Self::ChangeEpoch(_) => {
398                vec![InputObjectKind::SharedMoveObject {
399                    id: IOTA_SYSTEM_STATE_OBJECT_ID,
400                    initial_shared_version: IOTA_SYSTEM_STATE_OBJECT_SHARED_VERSION,
401                    mutable: true,
402                }]
403            }
404            Self::ChangeEpochV2(_) => {
405                vec![InputObjectKind::SharedMoveObject {
406                    id: IOTA_SYSTEM_STATE_OBJECT_ID,
407                    initial_shared_version: IOTA_SYSTEM_STATE_OBJECT_SHARED_VERSION,
408                    mutable: true,
409                }]
410            }
411            Self::AuthenticatorStateCreate => vec![],
412            Self::AuthenticatorStateExpire(expire) => {
413                vec![InputObjectKind::SharedMoveObject {
414                    id: IOTA_AUTHENTICATOR_STATE_OBJECT_ID,
415                    initial_shared_version: expire.authenticator_obj_initial_shared_version(),
416                    mutable: true,
417                }]
418            }
419        }
420    }
421
422    fn shared_input_objects(&self) -> impl Iterator<Item = SharedInputObject> + '_ {
423        match self {
424            Self::ChangeEpoch(_) => {
425                Either::Left(vec![SharedInputObject::IOTA_SYSTEM_OBJ].into_iter())
426            }
427            Self::ChangeEpochV2(_) => {
428                Either::Left(vec![SharedInputObject::IOTA_SYSTEM_OBJ].into_iter())
429            }
430            Self::AuthenticatorStateExpire(expire) => Either::Left(
431                vec![SharedInputObject {
432                    id: IOTA_AUTHENTICATOR_STATE_OBJECT_ID,
433                    initial_shared_version: expire.authenticator_obj_initial_shared_version(),
434                    mutable: true,
435                }]
436                .into_iter(),
437            ),
438            Self::AuthenticatorStateCreate => Either::Right(iter::empty()),
439        }
440    }
441
442    fn validity_check(&self, config: &ProtocolConfig) -> UserInputResult {
443        match self {
444            Self::ChangeEpoch(_) => {
445                if config.protocol_defined_base_fee() {
446                    return Err(UserInputError::Unsupported(
447                        "protocol defined base fee not supported".to_string(),
448                    ));
449                }
450            }
451            Self::ChangeEpochV2(_) => {
452                if !config.protocol_defined_base_fee() {
453                    return Err(UserInputError::Unsupported(
454                        "protocol defined base fee required".to_string(),
455                    ));
456                }
457            }
458            Self::AuthenticatorStateCreate | Self::AuthenticatorStateExpire(_) => {
459                if !config.enable_jwk_consensus_updates() {
460                    return Err(UserInputError::Unsupported(
461                        "authenticator state updates not enabled".to_string(),
462                    ));
463                }
464            }
465        }
466        Ok(())
467    }
468}
469
470impl CallArg {
471    fn input_objects(&self) -> Vec<InputObjectKind> {
472        match self {
473            CallArg::Pure(_) => vec![],
474            CallArg::Object(ObjectArg::ImmOrOwnedObject(object_ref)) => {
475                vec![InputObjectKind::ImmOrOwnedMoveObject(*object_ref)]
476            }
477            CallArg::Object(ObjectArg::SharedObject {
478                id,
479                initial_shared_version,
480                mutable,
481            }) => {
482                let id = *id;
483                let initial_shared_version = *initial_shared_version;
484                let mutable = *mutable;
485                vec![InputObjectKind::SharedMoveObject {
486                    id,
487                    initial_shared_version,
488                    mutable,
489                }]
490            }
491            // Receiving objects are not part of the input objects.
492            CallArg::Object(ObjectArg::Receiving(_)) => vec![],
493        }
494    }
495
496    fn receiving_objects(&self) -> Vec<ObjectRef> {
497        match self {
498            CallArg::Pure(_) => vec![],
499            CallArg::Object(o) => match o {
500                ObjectArg::ImmOrOwnedObject(_) => vec![],
501                ObjectArg::SharedObject { .. } => vec![],
502                ObjectArg::Receiving(obj_ref) => vec![*obj_ref],
503            },
504        }
505    }
506
507    pub fn validity_check(&self, config: &ProtocolConfig) -> UserInputResult {
508        match self {
509            CallArg::Pure(p) => {
510                fp_ensure!(
511                    p.len() < config.max_pure_argument_size() as usize,
512                    UserInputError::SizeLimitExceeded {
513                        limit: "maximum pure argument size".to_string(),
514                        value: config.max_pure_argument_size().to_string()
515                    }
516                );
517            }
518            CallArg::Object(o) => match o {
519                ObjectArg::Receiving(_)
520                | ObjectArg::ImmOrOwnedObject(_)
521                | ObjectArg::SharedObject { .. } => (),
522            },
523        }
524        Ok(())
525    }
526}
527
528impl From<bool> for CallArg {
529    fn from(b: bool) -> Self {
530        // unwrap safe because every u8 value is BCS-serializable
531        CallArg::Pure(bcs::to_bytes(&b).unwrap())
532    }
533}
534
535impl From<u8> for CallArg {
536    fn from(n: u8) -> Self {
537        // unwrap safe because every u8 value is BCS-serializable
538        CallArg::Pure(bcs::to_bytes(&n).unwrap())
539    }
540}
541
542impl From<u16> for CallArg {
543    fn from(n: u16) -> Self {
544        // unwrap safe because every u16 value is BCS-serializable
545        CallArg::Pure(bcs::to_bytes(&n).unwrap())
546    }
547}
548
549impl From<u32> for CallArg {
550    fn from(n: u32) -> Self {
551        // unwrap safe because every u32 value is BCS-serializable
552        CallArg::Pure(bcs::to_bytes(&n).unwrap())
553    }
554}
555
556impl From<u64> for CallArg {
557    fn from(n: u64) -> Self {
558        // unwrap safe because every u64 value is BCS-serializable
559        CallArg::Pure(bcs::to_bytes(&n).unwrap())
560    }
561}
562
563impl From<u128> for CallArg {
564    fn from(n: u128) -> Self {
565        // unwrap safe because every u128 value is BCS-serializable
566        CallArg::Pure(bcs::to_bytes(&n).unwrap())
567    }
568}
569
570impl From<&Vec<u8>> for CallArg {
571    fn from(v: &Vec<u8>) -> Self {
572        // unwrap safe because every vec<u8> value is BCS-serializable
573        CallArg::Pure(bcs::to_bytes(v).unwrap())
574    }
575}
576
577impl From<ObjectRef> for CallArg {
578    fn from(obj: ObjectRef) -> Self {
579        CallArg::Object(ObjectArg::ImmOrOwnedObject(obj))
580    }
581}
582
583impl ObjectArg {
584    pub const IOTA_SYSTEM_MUT: Self = Self::SharedObject {
585        id: IOTA_SYSTEM_STATE_OBJECT_ID,
586        initial_shared_version: IOTA_SYSTEM_STATE_OBJECT_SHARED_VERSION,
587        mutable: true,
588    };
589
590    pub fn id(&self) -> ObjectID {
591        match self {
592            ObjectArg::Receiving((id, _, _))
593            | ObjectArg::ImmOrOwnedObject((id, _, _))
594            | ObjectArg::SharedObject { id, .. } => *id,
595        }
596    }
597}
598
599// Add package IDs, `ObjectID`, for types defined in modules.
600fn add_type_tag_packages(packages: &mut BTreeSet<ObjectID>, type_argument: &TypeTag) {
601    let mut stack = vec![type_argument];
602    while let Some(cur) = stack.pop() {
603        match cur {
604            TypeTag::Bool
605            | TypeTag::U8
606            | TypeTag::U64
607            | TypeTag::U128
608            | TypeTag::Address
609            | TypeTag::Signer
610            | TypeTag::U16
611            | TypeTag::U32
612            | TypeTag::U256 => (),
613            TypeTag::Vector(inner) => stack.push(inner),
614            TypeTag::Struct(struct_tag) => {
615                packages.insert(struct_tag.address.into());
616                stack.extend(struct_tag.type_params.iter())
617            }
618        }
619    }
620}
621
622/// A series of commands where the results of one command can be used in future
623/// commands
624#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
625pub struct ProgrammableTransaction {
626    /// Input objects or primitive values
627    pub inputs: Vec<CallArg>,
628    /// The commands to be executed sequentially. A failure in any command will
629    /// result in the failure of the entire transaction.
630    pub commands: Vec<Command>,
631}
632
633/// A single command in a programmable transaction.
634#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
635pub enum Command {
636    /// A call to either an entry or a public Move function
637    MoveCall(Box<ProgrammableMoveCall>),
638    /// `(Vec<forall T:key+store. T>, address)`
639    /// It sends n-objects to the specified address. These objects must have
640    /// store (public transfer) and either the previous owner must be an
641    /// address or the object must be newly created.
642    TransferObjects(Vec<Argument>, Argument),
643    /// `(&mut Coin<T>, Vec<u64>)` -> `Vec<Coin<T>>`
644    /// It splits off some amounts into a new coins with those amounts
645    SplitCoins(Argument, Vec<Argument>),
646    /// `(&mut Coin<T>, Vec<Coin<T>>)`
647    /// It merges n-coins into the first coin
648    MergeCoins(Argument, Vec<Argument>),
649    /// Publishes a Move package. It takes the package bytes and a list of the
650    /// package's transitive dependencies to link against on-chain.
651    Publish(Vec<Vec<u8>>, Vec<ObjectID>),
652    /// `forall T: Vec<T> -> vector<T>`
653    /// Given n-values of the same type, it constructs a vector. For non objects
654    /// or an empty vector, the type tag must be specified.
655    MakeMoveVec(Option<TypeTag>, Vec<Argument>),
656    /// Upgrades a Move package
657    /// Takes (in order):
658    /// 1. A vector of serialized modules for the package.
659    /// 2. A vector of object ids for the transitive dependencies of the new
660    ///    package.
661    /// 3. The object ID of the package being upgraded.
662    /// 4. An argument holding the `UpgradeTicket` that must have been produced
663    ///    from an earlier command in the same programmable transaction.
664    Upgrade(Vec<Vec<u8>>, Vec<ObjectID>, ObjectID, Argument),
665}
666
667/// An argument to a programmable transaction command
668#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, Serialize, Deserialize)]
669pub enum Argument {
670    /// The gas coin. The gas coin can only be used by-ref, except for with
671    /// `TransferObjects`, which can use it by-value.
672    GasCoin,
673    /// One of the input objects or primitive values (from
674    /// `ProgrammableTransaction` inputs)
675    Input(u16),
676    /// The result of another command (from `ProgrammableTransaction` commands)
677    Result(u16),
678    /// Like a `Result` but it accesses a nested result. Currently, the only
679    /// usage of this is to access a value from a Move call with multiple
680    /// return values.
681    NestedResult(u16, u16),
682}
683
684/// The command for calling a Move function, either an entry function or a
685/// public function (which cannot return references).
686#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
687pub struct ProgrammableMoveCall {
688    /// The package containing the module and function.
689    pub package: ObjectID,
690    /// The specific module in the package containing the function.
691    pub module: Identifier,
692    /// The function to be called.
693    pub function: Identifier,
694    /// The type arguments to the function.
695    pub type_arguments: Vec<TypeTag>,
696    /// The arguments to the function.
697    pub arguments: Vec<Argument>,
698}
699
700impl ProgrammableMoveCall {
701    fn input_objects(&self) -> Vec<InputObjectKind> {
702        let ProgrammableMoveCall {
703            package,
704            type_arguments,
705            ..
706        } = self;
707        let mut packages = BTreeSet::from([*package]);
708        for type_argument in type_arguments {
709            add_type_tag_packages(&mut packages, type_argument)
710        }
711        packages
712            .into_iter()
713            .map(InputObjectKind::MovePackage)
714            .collect()
715    }
716
717    pub fn validity_check(&self, config: &ProtocolConfig) -> UserInputResult {
718        let is_blocked = BLOCKED_MOVE_FUNCTIONS.contains(&(
719            self.package,
720            self.module.as_str(),
721            self.function.as_str(),
722        ));
723        fp_ensure!(!is_blocked, UserInputError::BlockedMoveFunction);
724        let mut type_arguments_count = 0;
725        for tag in &self.type_arguments {
726            type_tag_validity_check(tag, config, &mut type_arguments_count)?;
727        }
728        fp_ensure!(
729            self.arguments.len() < config.max_arguments() as usize,
730            UserInputError::SizeLimitExceeded {
731                limit: "maximum arguments in a move call".to_string(),
732                value: config.max_arguments().to_string()
733            }
734        );
735        Ok(())
736    }
737
738    fn is_input_arg_used(&self, arg: u16) -> bool {
739        self.arguments
740            .iter()
741            .any(|a| matches!(a, Argument::Input(inp) if *inp == arg))
742    }
743}
744
745impl Command {
746    pub fn move_call(
747        package: ObjectID,
748        module: Identifier,
749        function: Identifier,
750        type_arguments: Vec<TypeTag>,
751        arguments: Vec<Argument>,
752    ) -> Self {
753        Command::MoveCall(Box::new(ProgrammableMoveCall {
754            package,
755            module,
756            function,
757            type_arguments,
758            arguments,
759        }))
760    }
761
762    fn input_objects(&self) -> Vec<InputObjectKind> {
763        match self {
764            Command::Upgrade(_, deps, package_id, _) => deps
765                .iter()
766                .map(|id| InputObjectKind::MovePackage(*id))
767                .chain(Some(InputObjectKind::MovePackage(*package_id)))
768                .collect(),
769            Command::Publish(_, deps) => deps
770                .iter()
771                .map(|id| InputObjectKind::MovePackage(*id))
772                .collect(),
773            Command::MoveCall(c) => c.input_objects(),
774            Command::MakeMoveVec(Some(t), _) => {
775                let mut packages = BTreeSet::new();
776                add_type_tag_packages(&mut packages, t);
777                packages
778                    .into_iter()
779                    .map(InputObjectKind::MovePackage)
780                    .collect()
781            }
782            Command::MakeMoveVec(None, _)
783            | Command::TransferObjects(_, _)
784            | Command::SplitCoins(_, _)
785            | Command::MergeCoins(_, _) => vec![],
786        }
787    }
788
789    fn non_system_packages_to_be_published(&self) -> Option<&Vec<Vec<u8>>> {
790        match self {
791            Command::Upgrade(v, _, _, _) => Some(v),
792            Command::Publish(v, _) => Some(v),
793            Command::MoveCall(_)
794            | Command::TransferObjects(_, _)
795            | Command::SplitCoins(_, _)
796            | Command::MergeCoins(_, _)
797            | Command::MakeMoveVec(_, _) => None,
798        }
799    }
800
801    fn validity_check(&self, config: &ProtocolConfig) -> UserInputResult {
802        match self {
803            Command::MoveCall(call) => call.validity_check(config)?,
804            Command::TransferObjects(args, _)
805            | Command::MergeCoins(_, args)
806            | Command::SplitCoins(_, args) => {
807                fp_ensure!(!args.is_empty(), UserInputError::EmptyCommandInput);
808                fp_ensure!(
809                    args.len() < config.max_arguments() as usize,
810                    UserInputError::SizeLimitExceeded {
811                        limit: "maximum arguments in a programmable transaction command"
812                            .to_string(),
813                        value: config.max_arguments().to_string()
814                    }
815                );
816            }
817            Command::MakeMoveVec(ty_opt, args) => {
818                // ty_opt.is_none() ==> !args.is_empty()
819                fp_ensure!(
820                    ty_opt.is_some() || !args.is_empty(),
821                    UserInputError::EmptyCommandInput
822                );
823                if let Some(ty) = ty_opt {
824                    let mut type_arguments_count = 0;
825                    type_tag_validity_check(ty, config, &mut type_arguments_count)?;
826                }
827                fp_ensure!(
828                    args.len() < config.max_arguments() as usize,
829                    UserInputError::SizeLimitExceeded {
830                        limit: "maximum arguments in a programmable transaction command"
831                            .to_string(),
832                        value: config.max_arguments().to_string()
833                    }
834                );
835            }
836            Command::Publish(modules, deps) | Command::Upgrade(modules, deps, _, _) => {
837                fp_ensure!(!modules.is_empty(), UserInputError::EmptyCommandInput);
838                fp_ensure!(
839                    modules.len() < config.max_modules_in_publish() as usize,
840                    UserInputError::SizeLimitExceeded {
841                        limit: "maximum modules in a programmable transaction upgrade command"
842                            .to_string(),
843                        value: config.max_modules_in_publish().to_string()
844                    }
845                );
846                if let Some(max_package_dependencies) = config.max_package_dependencies_as_option()
847                {
848                    fp_ensure!(
849                        deps.len() < max_package_dependencies as usize,
850                        UserInputError::SizeLimitExceeded {
851                            limit: "maximum package dependencies".to_string(),
852                            value: max_package_dependencies.to_string()
853                        }
854                    );
855                };
856            }
857        };
858        Ok(())
859    }
860
861    fn is_input_arg_used(&self, input_arg: u16) -> bool {
862        match self {
863            Command::MoveCall(c) => c.is_input_arg_used(input_arg),
864            Command::TransferObjects(args, arg)
865            | Command::MergeCoins(arg, args)
866            | Command::SplitCoins(arg, args) => args
867                .iter()
868                .chain(once(arg))
869                .any(|a| matches!(a, Argument::Input(inp) if *inp == input_arg)),
870            Command::MakeMoveVec(_, args) => args
871                .iter()
872                .any(|a| matches!(a, Argument::Input(inp) if *inp == input_arg)),
873            Command::Upgrade(_, _, _, arg) => {
874                matches!(arg, Argument::Input(inp) if *inp == input_arg)
875            }
876            Command::Publish(_, _) => false,
877        }
878    }
879}
880
881pub fn write_sep<T: Display>(
882    f: &mut Formatter<'_>,
883    items: impl IntoIterator<Item = T>,
884    sep: &str,
885) -> std::fmt::Result {
886    let mut xs = items.into_iter();
887    let Some(x) = xs.next() else {
888        return Ok(());
889    };
890    write!(f, "{x}")?;
891    for x in xs {
892        write!(f, "{sep}{x}")?;
893    }
894    Ok(())
895}
896
897impl ProgrammableTransaction {
898    pub fn input_objects(&self) -> UserInputResult<Vec<InputObjectKind>> {
899        let ProgrammableTransaction { inputs, commands } = self;
900        let input_arg_objects = inputs
901            .iter()
902            .flat_map(|arg| arg.input_objects())
903            .collect::<Vec<_>>();
904        // all objects, not just mutable, must be unique
905        let mut used = HashSet::new();
906        if !input_arg_objects.iter().all(|o| used.insert(o.object_id())) {
907            return Err(UserInputError::DuplicateObjectRefInput);
908        }
909        // do not duplicate packages referred to in commands
910        let command_input_objects: BTreeSet<InputObjectKind> = commands
911            .iter()
912            .flat_map(|command| command.input_objects())
913            .collect();
914        Ok(input_arg_objects
915            .into_iter()
916            .chain(command_input_objects)
917            .collect())
918    }
919
920    fn receiving_objects(&self) -> Vec<ObjectRef> {
921        let ProgrammableTransaction { inputs, .. } = self;
922        inputs
923            .iter()
924            .flat_map(|arg| arg.receiving_objects())
925            .collect()
926    }
927
928    fn validity_check(&self, config: &ProtocolConfig) -> UserInputResult {
929        let ProgrammableTransaction { inputs, commands } = self;
930        fp_ensure!(
931            commands.len() < config.max_programmable_tx_commands() as usize,
932            UserInputError::SizeLimitExceeded {
933                limit: "maximum commands in a programmable transaction".to_string(),
934                value: config.max_programmable_tx_commands().to_string()
935            }
936        );
937        let total_inputs = self.input_objects()?.len() + self.receiving_objects().len();
938        fp_ensure!(
939            total_inputs <= config.max_input_objects() as usize,
940            UserInputError::SizeLimitExceeded {
941                limit: "maximum input + receiving objects in a transaction".to_string(),
942                value: config.max_input_objects().to_string()
943            }
944        );
945        for input in inputs {
946            input.validity_check(config)?
947        }
948        if let Some(max_publish_commands) = config.max_publish_or_upgrade_per_ptb_as_option() {
949            let publish_count = commands
950                .iter()
951                .filter(|c| matches!(c, Command::Publish(_, _) | Command::Upgrade(_, _, _, _)))
952                .count() as u64;
953            fp_ensure!(
954                publish_count <= max_publish_commands,
955                UserInputError::MaxPublishCountExceeded {
956                    max_publish_commands,
957                    publish_count,
958                }
959            );
960        }
961        for command in commands {
962            command.validity_check(config)?;
963        }
964
965        // If randomness is used, it must be enabled by protocol config.
966        // A command that uses Random can only be followed by TransferObjects or
967        // MergeCoins.
968        if let Some(random_index) = inputs.iter().position(|obj| {
969            matches!(obj, CallArg::Object(ObjectArg::SharedObject { id, .. }) if *id == IOTA_RANDOMNESS_STATE_OBJECT_ID)
970        }) {
971            let mut used_random_object = false;
972            let random_index = random_index.try_into().unwrap();
973            for command in commands {
974                if !used_random_object {
975                    used_random_object = command.is_input_arg_used(random_index);
976                } else {
977                    fp_ensure!(
978                        matches!(
979                            command,
980                            Command::TransferObjects(_, _) | Command::MergeCoins(_, _)
981                        ),
982                        UserInputError::PostRandomCommandRestrictions
983                    );
984                }
985            }
986        }
987
988        Ok(())
989    }
990
991    fn shared_input_objects(&self) -> impl Iterator<Item = SharedInputObject> + '_ {
992        self.inputs
993            .iter()
994            .filter_map(|arg| match arg {
995                CallArg::Pure(_)
996                | CallArg::Object(ObjectArg::Receiving(_))
997                | CallArg::Object(ObjectArg::ImmOrOwnedObject(_)) => None,
998                CallArg::Object(ObjectArg::SharedObject {
999                    id,
1000                    initial_shared_version,
1001                    mutable,
1002                }) => Some(vec![SharedInputObject {
1003                    id: *id,
1004                    initial_shared_version: *initial_shared_version,
1005                    mutable: *mutable,
1006                }]),
1007            })
1008            .flatten()
1009    }
1010
1011    fn move_calls(&self) -> Vec<(&ObjectID, &IdentStr, &IdentStr)> {
1012        self.commands
1013            .iter()
1014            .filter_map(|command| match command {
1015                Command::MoveCall(m) => Some((
1016                    &m.package,
1017                    m.module.as_ident_str(),
1018                    m.function.as_ident_str(),
1019                )),
1020                _ => None,
1021            })
1022            .collect()
1023    }
1024
1025    pub fn non_system_packages_to_be_published(&self) -> impl Iterator<Item = &Vec<Vec<u8>>> + '_ {
1026        self.commands
1027            .iter()
1028            .filter_map(|q| q.non_system_packages_to_be_published())
1029    }
1030}
1031
1032impl Display for Argument {
1033    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1034        match self {
1035            Argument::GasCoin => write!(f, "GasCoin"),
1036            Argument::Input(i) => write!(f, "Input({i})"),
1037            Argument::Result(i) => write!(f, "Result({i})"),
1038            Argument::NestedResult(i, j) => write!(f, "NestedResult({i},{j})"),
1039        }
1040    }
1041}
1042
1043impl Display for ProgrammableMoveCall {
1044    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1045        let ProgrammableMoveCall {
1046            package,
1047            module,
1048            function,
1049            type_arguments,
1050            arguments,
1051        } = self;
1052        write!(f, "{package}::{module}::{function}")?;
1053        if !type_arguments.is_empty() {
1054            write!(f, "<")?;
1055            write_sep(f, type_arguments, ",")?;
1056            write!(f, ">")?;
1057        }
1058        write!(f, "(")?;
1059        write_sep(f, arguments, ",")?;
1060        write!(f, ")")
1061    }
1062}
1063
1064impl Display for Command {
1065    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1066        match self {
1067            Command::MoveCall(p) => {
1068                write!(f, "MoveCall({p})")
1069            }
1070            Command::MakeMoveVec(ty_opt, elems) => {
1071                write!(f, "MakeMoveVec(")?;
1072                if let Some(ty) = ty_opt {
1073                    write!(f, "Some{ty}")?;
1074                } else {
1075                    write!(f, "None")?;
1076                }
1077                write!(f, ",[")?;
1078                write_sep(f, elems, ",")?;
1079                write!(f, "])")
1080            }
1081            Command::TransferObjects(objs, addr) => {
1082                write!(f, "TransferObjects([")?;
1083                write_sep(f, objs, ",")?;
1084                write!(f, "],{addr})")
1085            }
1086            Command::SplitCoins(coin, amounts) => {
1087                write!(f, "SplitCoins({coin}")?;
1088                write_sep(f, amounts, ",")?;
1089                write!(f, ")")
1090            }
1091            Command::MergeCoins(target, coins) => {
1092                write!(f, "MergeCoins({target},")?;
1093                write_sep(f, coins, ",")?;
1094                write!(f, ")")
1095            }
1096            Command::Publish(_bytes, deps) => {
1097                write!(f, "Publish(_,")?;
1098                write_sep(f, deps, ",")?;
1099                write!(f, ")")
1100            }
1101            Command::Upgrade(_bytes, deps, current_package_id, ticket) => {
1102                write!(f, "Upgrade(_,")?;
1103                write_sep(f, deps, ",")?;
1104                write!(f, ", {current_package_id}")?;
1105                write!(f, ", {ticket}")?;
1106                write!(f, ")")
1107            }
1108        }
1109    }
1110}
1111
1112impl Display for ProgrammableTransaction {
1113    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1114        let ProgrammableTransaction { inputs, commands } = self;
1115        writeln!(f, "Inputs: {inputs:?}")?;
1116        writeln!(f, "Commands: [")?;
1117        for c in commands {
1118            writeln!(f, "  {c},")?;
1119        }
1120        writeln!(f, "]")
1121    }
1122}
1123
1124#[derive(Debug, PartialEq, Eq)]
1125pub struct SharedInputObject {
1126    pub id: ObjectID,
1127    pub initial_shared_version: SequenceNumber,
1128    pub mutable: bool,
1129}
1130
1131impl SharedInputObject {
1132    pub const IOTA_SYSTEM_OBJ: Self = Self {
1133        id: IOTA_SYSTEM_STATE_OBJECT_ID,
1134        initial_shared_version: IOTA_SYSTEM_STATE_OBJECT_SHARED_VERSION,
1135        mutable: true,
1136    };
1137
1138    pub fn id(&self) -> ObjectID {
1139        self.id
1140    }
1141
1142    pub fn into_id_and_version(self) -> (ObjectID, SequenceNumber) {
1143        (self.id, self.initial_shared_version)
1144    }
1145}
1146
1147impl TransactionKind {
1148    /// present to make migrations to programmable transactions eaier.
1149    /// Will be removed
1150    pub fn programmable(pt: ProgrammableTransaction) -> Self {
1151        TransactionKind::ProgrammableTransaction(pt)
1152    }
1153
1154    pub fn is_system_tx(&self) -> bool {
1155        // Keep this as an exhaustive match so that we can't forget to update it.
1156        match self {
1157            TransactionKind::Genesis(_)
1158            | TransactionKind::ConsensusCommitPrologueV1(_)
1159            | TransactionKind::AuthenticatorStateUpdateV1(_)
1160            | TransactionKind::RandomnessStateUpdate(_)
1161            | TransactionKind::EndOfEpochTransaction(_) => true,
1162            TransactionKind::ProgrammableTransaction(_) => false,
1163        }
1164    }
1165
1166    pub fn is_end_of_epoch_tx(&self) -> bool {
1167        matches!(self, TransactionKind::EndOfEpochTransaction(_))
1168    }
1169
1170    /// If this is advance epoch transaction, returns (total gas charged, total
1171    /// gas rebated). TODO: We should use GasCostSummary directly in
1172    /// ChangeEpoch struct, and return that directly.
1173    pub fn get_advance_epoch_tx_gas_summary(&self) -> Option<(u64, u64)> {
1174        match self {
1175            Self::EndOfEpochTransaction(txns) => {
1176                match txns.last().expect("at least one end-of-epoch txn required") {
1177                    EndOfEpochTransactionKind::ChangeEpoch(e) => {
1178                        Some((e.computation_charge + e.storage_charge, e.storage_rebate))
1179                    }
1180                    EndOfEpochTransactionKind::ChangeEpochV2(e) => {
1181                        Some((e.computation_charge + e.storage_charge, e.storage_rebate))
1182                    }
1183                    _ => panic!("final end-of-epoch txn must be ChangeEpoch"),
1184                }
1185            }
1186            _ => None,
1187        }
1188    }
1189
1190    pub fn contains_shared_object(&self) -> bool {
1191        self.shared_input_objects().next().is_some()
1192    }
1193
1194    /// Returns an iterator of all shared input objects used by this
1195    /// transaction.
1196    pub fn shared_input_objects(&self) -> impl Iterator<Item = SharedInputObject> + '_ {
1197        match &self {
1198            Self::ConsensusCommitPrologueV1(_) => {
1199                Either::Left(Either::Left(iter::once(SharedInputObject {
1200                    id: IOTA_CLOCK_OBJECT_ID,
1201                    initial_shared_version: IOTA_CLOCK_OBJECT_SHARED_VERSION,
1202                    mutable: true,
1203                })))
1204            }
1205            Self::AuthenticatorStateUpdateV1(update) => {
1206                Either::Left(Either::Left(iter::once(SharedInputObject {
1207                    id: IOTA_AUTHENTICATOR_STATE_OBJECT_ID,
1208                    initial_shared_version: update.authenticator_obj_initial_shared_version,
1209                    mutable: true,
1210                })))
1211            }
1212            Self::RandomnessStateUpdate(update) => {
1213                Either::Left(Either::Left(iter::once(SharedInputObject {
1214                    id: IOTA_RANDOMNESS_STATE_OBJECT_ID,
1215                    initial_shared_version: update.randomness_obj_initial_shared_version,
1216                    mutable: true,
1217                })))
1218            }
1219            Self::EndOfEpochTransaction(txns) => Either::Left(Either::Right(
1220                txns.iter().flat_map(|txn| txn.shared_input_objects()),
1221            )),
1222            Self::ProgrammableTransaction(pt) => {
1223                Either::Right(Either::Left(pt.shared_input_objects()))
1224            }
1225            _ => Either::Right(Either::Right(iter::empty())),
1226        }
1227    }
1228
1229    fn move_calls(&self) -> Vec<(&ObjectID, &IdentStr, &IdentStr)> {
1230        match &self {
1231            Self::ProgrammableTransaction(pt) => pt.move_calls(),
1232            _ => vec![],
1233        }
1234    }
1235
1236    pub fn receiving_objects(&self) -> Vec<ObjectRef> {
1237        match &self {
1238            TransactionKind::Genesis(_)
1239            | TransactionKind::ConsensusCommitPrologueV1(_)
1240            | TransactionKind::AuthenticatorStateUpdateV1(_)
1241            | TransactionKind::RandomnessStateUpdate(_)
1242            | TransactionKind::EndOfEpochTransaction(_) => vec![],
1243            TransactionKind::ProgrammableTransaction(pt) => pt.receiving_objects(),
1244        }
1245    }
1246
1247    /// Return the metadata of each of the input objects for the transaction.
1248    /// For a Move object, we attach the object reference;
1249    /// for a Move package, we provide the object id only since they never
1250    /// change on chain. TODO: use an iterator over references here instead
1251    /// of a Vec to avoid allocations.
1252    pub fn input_objects(&self) -> UserInputResult<Vec<InputObjectKind>> {
1253        let input_objects = match &self {
1254            Self::Genesis(_) => {
1255                vec![]
1256            }
1257            Self::ConsensusCommitPrologueV1(_) => {
1258                vec![InputObjectKind::SharedMoveObject {
1259                    id: IOTA_CLOCK_OBJECT_ID,
1260                    initial_shared_version: IOTA_CLOCK_OBJECT_SHARED_VERSION,
1261                    mutable: true,
1262                }]
1263            }
1264            Self::AuthenticatorStateUpdateV1(update) => {
1265                vec![InputObjectKind::SharedMoveObject {
1266                    id: IOTA_AUTHENTICATOR_STATE_OBJECT_ID,
1267                    initial_shared_version: update.authenticator_obj_initial_shared_version(),
1268                    mutable: true,
1269                }]
1270            }
1271            Self::RandomnessStateUpdate(update) => {
1272                vec![InputObjectKind::SharedMoveObject {
1273                    id: IOTA_RANDOMNESS_STATE_OBJECT_ID,
1274                    initial_shared_version: update.randomness_obj_initial_shared_version(),
1275                    mutable: true,
1276                }]
1277            }
1278            Self::EndOfEpochTransaction(txns) => {
1279                // Dedup since transactions may have an overlap in input objects.
1280                // Note: it's critical to ensure the order of inputs are deterministic.
1281                let before_dedup: Vec<_> =
1282                    txns.iter().flat_map(|txn| txn.input_objects()).collect();
1283                let mut has_seen = HashSet::new();
1284                let mut after_dedup = vec![];
1285                for obj in before_dedup {
1286                    if has_seen.insert(obj) {
1287                        after_dedup.push(obj);
1288                    }
1289                }
1290                after_dedup
1291            }
1292            Self::ProgrammableTransaction(p) => return p.input_objects(),
1293        };
1294        // Ensure that there are no duplicate inputs. This cannot be removed because:
1295        // In [`AuthorityState::check_locks`], we check that there are no duplicate
1296        // mutable input objects, which would have made this check here
1297        // unnecessary. However, we do plan to allow shared objects show up more
1298        // than once in multiple single transactions down the line. Once we have
1299        // that, we need check here to make sure the same shared object doesn't
1300        // show up more than once in the same single transaction.
1301        let mut used = HashSet::new();
1302        if !input_objects.iter().all(|o| used.insert(o.object_id())) {
1303            return Err(UserInputError::DuplicateObjectRefInput);
1304        }
1305        Ok(input_objects)
1306    }
1307
1308    pub fn validity_check(&self, config: &ProtocolConfig) -> UserInputResult {
1309        match self {
1310            TransactionKind::ProgrammableTransaction(p) => p.validity_check(config)?,
1311            // All transaction kinds below are assumed to be system,
1312            // and no validity or limit checks are performed.
1313            TransactionKind::Genesis(_) | TransactionKind::ConsensusCommitPrologueV1(_) => (),
1314            TransactionKind::EndOfEpochTransaction(txns) => {
1315                for tx in txns {
1316                    tx.validity_check(config)?;
1317                }
1318            }
1319
1320            TransactionKind::AuthenticatorStateUpdateV1(_) => {
1321                if !config.enable_jwk_consensus_updates() {
1322                    return Err(UserInputError::Unsupported(
1323                        "authenticator state updates not enabled".to_string(),
1324                    ));
1325                }
1326            }
1327            TransactionKind::RandomnessStateUpdate(_) => (),
1328        };
1329        Ok(())
1330    }
1331
1332    /// number of commands, or 0 if it is a system transaction
1333    pub fn num_commands(&self) -> usize {
1334        match self {
1335            TransactionKind::ProgrammableTransaction(pt) => pt.commands.len(),
1336            _ => 0,
1337        }
1338    }
1339
1340    pub fn iter_commands(&self) -> impl Iterator<Item = &Command> {
1341        match self {
1342            TransactionKind::ProgrammableTransaction(pt) => pt.commands.iter(),
1343            _ => [].iter(),
1344        }
1345    }
1346
1347    /// number of transactions, or 1 if it is a system transaction
1348    pub fn tx_count(&self) -> usize {
1349        match self {
1350            TransactionKind::ProgrammableTransaction(pt) => pt.commands.len(),
1351            _ => 1,
1352        }
1353    }
1354
1355    pub fn name(&self) -> &'static str {
1356        match self {
1357            Self::Genesis(_) => "Genesis",
1358            Self::ConsensusCommitPrologueV1(_) => "ConsensusCommitPrologueV1",
1359            Self::ProgrammableTransaction(_) => "ProgrammableTransaction",
1360            Self::AuthenticatorStateUpdateV1(_) => "AuthenticatorStateUpdateV1",
1361            Self::RandomnessStateUpdate(_) => "RandomnessStateUpdate",
1362            Self::EndOfEpochTransaction(_) => "EndOfEpochTransaction",
1363        }
1364    }
1365}
1366
1367impl Display for TransactionKind {
1368    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1369        let mut writer = String::new();
1370        match &self {
1371            Self::Genesis(_) => {
1372                writeln!(writer, "Transaction Kind : Genesis")?;
1373            }
1374            Self::ConsensusCommitPrologueV1(p) => {
1375                writeln!(writer, "Transaction Kind : Consensus Commit Prologue V1")?;
1376                writeln!(writer, "Timestamp : {}", p.commit_timestamp_ms)?;
1377                writeln!(writer, "Consensus Digest: {}", p.consensus_commit_digest)?;
1378                writeln!(
1379                    writer,
1380                    "Consensus determined version assignment: {:?}",
1381                    p.consensus_determined_version_assignments
1382                )?;
1383            }
1384            Self::ProgrammableTransaction(p) => {
1385                writeln!(writer, "Transaction Kind : Programmable")?;
1386                write!(writer, "{p}")?;
1387            }
1388            Self::AuthenticatorStateUpdateV1(_) => {
1389                writeln!(writer, "Transaction Kind : Authenticator State Update")?;
1390            }
1391            Self::RandomnessStateUpdate(_) => {
1392                writeln!(writer, "Transaction Kind : Randomness State Update")?;
1393            }
1394            Self::EndOfEpochTransaction(_) => {
1395                writeln!(writer, "Transaction Kind : End of Epoch Transaction")?;
1396            }
1397        }
1398        write!(f, "{}", writer)
1399    }
1400}
1401
1402#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
1403pub struct GasData {
1404    pub payment: Vec<ObjectRef>,
1405    pub owner: IotaAddress,
1406    pub price: u64,
1407    pub budget: u64,
1408}
1409
1410#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, Serialize, Deserialize)]
1411pub enum TransactionExpiration {
1412    /// The transaction has no expiration
1413    None,
1414    /// Validators wont sign a transaction unless the expiration Epoch
1415    /// is greater than or equal to the current epoch
1416    Epoch(EpochId),
1417}
1418
1419#[enum_dispatch(TransactionDataAPI)]
1420#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
1421pub enum TransactionData {
1422    V1(TransactionDataV1),
1423    // When new variants are introduced, it is important that we check version support
1424    // in the validity_check function based on the protocol config.
1425}
1426
1427#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
1428pub struct TransactionDataV1 {
1429    pub kind: TransactionKind,
1430    pub sender: IotaAddress,
1431    pub gas_data: GasData,
1432    pub expiration: TransactionExpiration,
1433}
1434
1435impl TransactionData {
1436    fn new_system_transaction(kind: TransactionKind) -> Self {
1437        // assert transaction kind if a system transaction
1438        assert!(kind.is_system_tx());
1439        let sender = IotaAddress::default();
1440        TransactionData::V1(TransactionDataV1 {
1441            kind,
1442            sender,
1443            gas_data: GasData {
1444                price: GAS_PRICE_FOR_SYSTEM_TX,
1445                owner: sender,
1446                payment: vec![(ObjectID::ZERO, SequenceNumber::default(), ObjectDigest::MIN)],
1447                budget: 0,
1448            },
1449            expiration: TransactionExpiration::None,
1450        })
1451    }
1452
1453    pub fn new(
1454        kind: TransactionKind,
1455        sender: IotaAddress,
1456        gas_payment: ObjectRef,
1457        gas_budget: u64,
1458        gas_price: u64,
1459    ) -> Self {
1460        TransactionData::V1(TransactionDataV1 {
1461            kind,
1462            sender,
1463            gas_data: GasData {
1464                price: gas_price,
1465                owner: sender,
1466                payment: vec![gas_payment],
1467                budget: gas_budget,
1468            },
1469            expiration: TransactionExpiration::None,
1470        })
1471    }
1472
1473    pub fn new_with_gas_coins(
1474        kind: TransactionKind,
1475        sender: IotaAddress,
1476        gas_payment: Vec<ObjectRef>,
1477        gas_budget: u64,
1478        gas_price: u64,
1479    ) -> Self {
1480        Self::new_with_gas_coins_allow_sponsor(
1481            kind,
1482            sender,
1483            gas_payment,
1484            gas_budget,
1485            gas_price,
1486            sender,
1487        )
1488    }
1489
1490    pub fn new_with_gas_coins_allow_sponsor(
1491        kind: TransactionKind,
1492        sender: IotaAddress,
1493        gas_payment: Vec<ObjectRef>,
1494        gas_budget: u64,
1495        gas_price: u64,
1496        gas_sponsor: IotaAddress,
1497    ) -> Self {
1498        TransactionData::V1(TransactionDataV1 {
1499            kind,
1500            sender,
1501            gas_data: GasData {
1502                price: gas_price,
1503                owner: gas_sponsor,
1504                payment: gas_payment,
1505                budget: gas_budget,
1506            },
1507            expiration: TransactionExpiration::None,
1508        })
1509    }
1510
1511    pub fn new_with_gas_data(
1512        kind: TransactionKind,
1513        sender: IotaAddress,
1514        gas_data: GasData,
1515    ) -> Self {
1516        TransactionData::V1(TransactionDataV1 {
1517            kind,
1518            sender,
1519            gas_data,
1520            expiration: TransactionExpiration::None,
1521        })
1522    }
1523
1524    pub fn new_move_call(
1525        sender: IotaAddress,
1526        package: ObjectID,
1527        module: Identifier,
1528        function: Identifier,
1529        type_arguments: Vec<TypeTag>,
1530        gas_payment: ObjectRef,
1531        arguments: Vec<CallArg>,
1532        gas_budget: u64,
1533        gas_price: u64,
1534    ) -> anyhow::Result<Self> {
1535        Self::new_move_call_with_gas_coins(
1536            sender,
1537            package,
1538            module,
1539            function,
1540            type_arguments,
1541            vec![gas_payment],
1542            arguments,
1543            gas_budget,
1544            gas_price,
1545        )
1546    }
1547
1548    pub fn new_move_call_with_gas_coins(
1549        sender: IotaAddress,
1550        package: ObjectID,
1551        module: Identifier,
1552        function: Identifier,
1553        type_arguments: Vec<TypeTag>,
1554        gas_payment: Vec<ObjectRef>,
1555        arguments: Vec<CallArg>,
1556        gas_budget: u64,
1557        gas_price: u64,
1558    ) -> anyhow::Result<Self> {
1559        let pt = {
1560            let mut builder = ProgrammableTransactionBuilder::new();
1561            builder.move_call(package, module, function, type_arguments, arguments)?;
1562            builder.finish()
1563        };
1564        Ok(Self::new_programmable(
1565            sender,
1566            gas_payment,
1567            pt,
1568            gas_budget,
1569            gas_price,
1570        ))
1571    }
1572
1573    pub fn new_transfer(
1574        recipient: IotaAddress,
1575        object_ref: ObjectRef,
1576        sender: IotaAddress,
1577        gas_payment: ObjectRef,
1578        gas_budget: u64,
1579        gas_price: u64,
1580    ) -> Self {
1581        let pt = {
1582            let mut builder = ProgrammableTransactionBuilder::new();
1583            builder.transfer_object(recipient, object_ref).unwrap();
1584            builder.finish()
1585        };
1586        Self::new_programmable(sender, vec![gas_payment], pt, gas_budget, gas_price)
1587    }
1588
1589    pub fn new_transfer_iota(
1590        recipient: IotaAddress,
1591        sender: IotaAddress,
1592        amount: Option<u64>,
1593        gas_payment: ObjectRef,
1594        gas_budget: u64,
1595        gas_price: u64,
1596    ) -> Self {
1597        Self::new_transfer_iota_allow_sponsor(
1598            recipient,
1599            sender,
1600            amount,
1601            gas_payment,
1602            gas_budget,
1603            gas_price,
1604            sender,
1605        )
1606    }
1607
1608    pub fn new_transfer_iota_allow_sponsor(
1609        recipient: IotaAddress,
1610        sender: IotaAddress,
1611        amount: Option<u64>,
1612        gas_payment: ObjectRef,
1613        gas_budget: u64,
1614        gas_price: u64,
1615        gas_sponsor: IotaAddress,
1616    ) -> Self {
1617        let pt = {
1618            let mut builder = ProgrammableTransactionBuilder::new();
1619            builder.transfer_iota(recipient, amount);
1620            builder.finish()
1621        };
1622        Self::new_programmable_allow_sponsor(
1623            sender,
1624            vec![gas_payment],
1625            pt,
1626            gas_budget,
1627            gas_price,
1628            gas_sponsor,
1629        )
1630    }
1631
1632    pub fn new_pay(
1633        sender: IotaAddress,
1634        coins: Vec<ObjectRef>,
1635        recipients: Vec<IotaAddress>,
1636        amounts: Vec<u64>,
1637        gas_payment: ObjectRef,
1638        gas_budget: u64,
1639        gas_price: u64,
1640    ) -> anyhow::Result<Self> {
1641        let pt = {
1642            let mut builder = ProgrammableTransactionBuilder::new();
1643            builder.pay(coins, recipients, amounts)?;
1644            builder.finish()
1645        };
1646        Ok(Self::new_programmable(
1647            sender,
1648            vec![gas_payment],
1649            pt,
1650            gas_budget,
1651            gas_price,
1652        ))
1653    }
1654
1655    pub fn new_pay_iota(
1656        sender: IotaAddress,
1657        mut coins: Vec<ObjectRef>,
1658        recipients: Vec<IotaAddress>,
1659        amounts: Vec<u64>,
1660        gas_payment: ObjectRef,
1661        gas_budget: u64,
1662        gas_price: u64,
1663    ) -> anyhow::Result<Self> {
1664        coins.insert(0, gas_payment);
1665        let pt = {
1666            let mut builder = ProgrammableTransactionBuilder::new();
1667            builder.pay_iota(recipients, amounts)?;
1668            builder.finish()
1669        };
1670        Ok(Self::new_programmable(
1671            sender, coins, pt, gas_budget, gas_price,
1672        ))
1673    }
1674
1675    pub fn new_pay_all_iota(
1676        sender: IotaAddress,
1677        mut coins: Vec<ObjectRef>,
1678        recipient: IotaAddress,
1679        gas_payment: ObjectRef,
1680        gas_budget: u64,
1681        gas_price: u64,
1682    ) -> Self {
1683        coins.insert(0, gas_payment);
1684        let pt = {
1685            let mut builder = ProgrammableTransactionBuilder::new();
1686            builder.pay_all_iota(recipient);
1687            builder.finish()
1688        };
1689        Self::new_programmable(sender, coins, pt, gas_budget, gas_price)
1690    }
1691
1692    pub fn new_module(
1693        sender: IotaAddress,
1694        gas_payment: ObjectRef,
1695        modules: Vec<Vec<u8>>,
1696        dep_ids: Vec<ObjectID>,
1697        gas_budget: u64,
1698        gas_price: u64,
1699    ) -> Self {
1700        let pt = {
1701            let mut builder = ProgrammableTransactionBuilder::new();
1702            let upgrade_cap = builder.publish_upgradeable(modules, dep_ids);
1703            builder.transfer_arg(sender, upgrade_cap);
1704            builder.finish()
1705        };
1706        Self::new_programmable(sender, vec![gas_payment], pt, gas_budget, gas_price)
1707    }
1708
1709    pub fn new_upgrade(
1710        sender: IotaAddress,
1711        gas_payment: ObjectRef,
1712        package_id: ObjectID,
1713        modules: Vec<Vec<u8>>,
1714        dep_ids: Vec<ObjectID>,
1715        (upgrade_capability, capability_owner): (ObjectRef, Owner),
1716        upgrade_policy: u8,
1717        digest: Vec<u8>,
1718        gas_budget: u64,
1719        gas_price: u64,
1720    ) -> anyhow::Result<Self> {
1721        let pt = {
1722            let mut builder = ProgrammableTransactionBuilder::new();
1723            let capability_arg = match capability_owner {
1724                Owner::AddressOwner(_) => ObjectArg::ImmOrOwnedObject(upgrade_capability),
1725                Owner::Shared {
1726                    initial_shared_version,
1727                } => ObjectArg::SharedObject {
1728                    id: upgrade_capability.0,
1729                    initial_shared_version,
1730                    mutable: true,
1731                },
1732                Owner::Immutable => {
1733                    bail!("Upgrade capability is stored immutably and cannot be used for upgrades");
1734                }
1735                // If the capability is owned by an object, then the module defining the owning
1736                // object gets to decide how the upgrade capability should be used.
1737                Owner::ObjectOwner(_) => {
1738                    bail!("Upgrade capability controlled by object");
1739                }
1740            };
1741            builder.obj(capability_arg).unwrap();
1742            let upgrade_arg = builder.pure(upgrade_policy).unwrap();
1743            let digest_arg = builder.pure(digest).unwrap();
1744            let upgrade_ticket = builder.programmable_move_call(
1745                IOTA_FRAMEWORK_PACKAGE_ID,
1746                ident_str!("package").to_owned(),
1747                ident_str!("authorize_upgrade").to_owned(),
1748                vec![],
1749                vec![Argument::Input(0), upgrade_arg, digest_arg],
1750            );
1751            let upgrade_receipt = builder.upgrade(package_id, upgrade_ticket, dep_ids, modules);
1752
1753            builder.programmable_move_call(
1754                IOTA_FRAMEWORK_PACKAGE_ID,
1755                ident_str!("package").to_owned(),
1756                ident_str!("commit_upgrade").to_owned(),
1757                vec![],
1758                vec![Argument::Input(0), upgrade_receipt],
1759            );
1760
1761            builder.finish()
1762        };
1763        Ok(Self::new_programmable(
1764            sender,
1765            vec![gas_payment],
1766            pt,
1767            gas_budget,
1768            gas_price,
1769        ))
1770    }
1771
1772    pub fn new_programmable(
1773        sender: IotaAddress,
1774        gas_payment: Vec<ObjectRef>,
1775        pt: ProgrammableTransaction,
1776        gas_budget: u64,
1777        gas_price: u64,
1778    ) -> Self {
1779        Self::new_programmable_allow_sponsor(sender, gas_payment, pt, gas_budget, gas_price, sender)
1780    }
1781
1782    pub fn new_programmable_allow_sponsor(
1783        sender: IotaAddress,
1784        gas_payment: Vec<ObjectRef>,
1785        pt: ProgrammableTransaction,
1786        gas_budget: u64,
1787        gas_price: u64,
1788        sponsor: IotaAddress,
1789    ) -> Self {
1790        let kind = TransactionKind::ProgrammableTransaction(pt);
1791        Self::new_with_gas_coins_allow_sponsor(
1792            kind,
1793            sender,
1794            gas_payment,
1795            gas_budget,
1796            gas_price,
1797            sponsor,
1798        )
1799    }
1800
1801    pub fn message_version(&self) -> u64 {
1802        match self {
1803            TransactionData::V1(_) => 1,
1804        }
1805    }
1806
1807    pub fn execution_parts(&self) -> (TransactionKind, IotaAddress, Vec<ObjectRef>) {
1808        (
1809            self.kind().clone(),
1810            self.sender(),
1811            self.gas_data().payment.clone(),
1812        )
1813    }
1814
1815    pub fn uses_randomness(&self) -> bool {
1816        self.shared_input_objects()
1817            .iter()
1818            .any(|obj| obj.id() == IOTA_RANDOMNESS_STATE_OBJECT_ID)
1819    }
1820
1821    pub fn digest(&self) -> TransactionDigest {
1822        TransactionDigest::new(default_hash(self))
1823    }
1824}
1825
1826#[enum_dispatch]
1827pub trait TransactionDataAPI {
1828    fn sender(&self) -> IotaAddress;
1829
1830    // Note: this implies that SingleTransactionKind itself must be versioned, so
1831    // that it can be shared across versions. This will be easy to do since it
1832    // is already an enum.
1833    fn kind(&self) -> &TransactionKind;
1834
1835    // Used by programmable_transaction_builder
1836    fn kind_mut(&mut self) -> &mut TransactionKind;
1837
1838    // kind is moved out of often enough that this is worth it to special case.
1839    fn into_kind(self) -> TransactionKind;
1840
1841    /// Transaction signer and Gas owner
1842    fn signers(&self) -> NonEmpty<IotaAddress>;
1843
1844    fn gas_data(&self) -> &GasData;
1845
1846    fn gas_owner(&self) -> IotaAddress;
1847
1848    fn gas(&self) -> &[ObjectRef];
1849
1850    fn gas_price(&self) -> u64;
1851
1852    fn gas_budget(&self) -> u64;
1853
1854    fn expiration(&self) -> &TransactionExpiration;
1855
1856    fn contains_shared_object(&self) -> bool;
1857
1858    fn shared_input_objects(&self) -> Vec<SharedInputObject>;
1859
1860    fn move_calls(&self) -> Vec<(&ObjectID, &IdentStr, &IdentStr)>;
1861
1862    fn input_objects(&self) -> UserInputResult<Vec<InputObjectKind>>;
1863
1864    fn receiving_objects(&self) -> Vec<ObjectRef>;
1865
1866    fn validity_check(&self, config: &ProtocolConfig) -> UserInputResult;
1867
1868    fn validity_check_no_gas_check(&self, config: &ProtocolConfig) -> UserInputResult;
1869
1870    /// Check if the transaction is compliant with sponsorship.
1871    fn check_sponsorship(&self) -> UserInputResult;
1872
1873    fn is_system_tx(&self) -> bool;
1874    fn is_genesis_tx(&self) -> bool;
1875
1876    /// returns true if the transaction is one that is specially sequenced to
1877    /// run at the very end of the epoch
1878    fn is_end_of_epoch_tx(&self) -> bool;
1879
1880    /// Check if the transaction is sponsored (namely gas owner != sender)
1881    fn is_sponsored_tx(&self) -> bool;
1882
1883    fn sender_mut_for_testing(&mut self) -> &mut IotaAddress;
1884
1885    fn gas_data_mut(&mut self) -> &mut GasData;
1886
1887    // This should be used in testing only.
1888    fn expiration_mut_for_testing(&mut self) -> &mut TransactionExpiration;
1889}
1890
1891impl TransactionDataAPI for TransactionDataV1 {
1892    fn sender(&self) -> IotaAddress {
1893        self.sender
1894    }
1895
1896    fn kind(&self) -> &TransactionKind {
1897        &self.kind
1898    }
1899
1900    fn kind_mut(&mut self) -> &mut TransactionKind {
1901        &mut self.kind
1902    }
1903
1904    fn into_kind(self) -> TransactionKind {
1905        self.kind
1906    }
1907
1908    /// Transaction signer and Gas owner
1909    fn signers(&self) -> NonEmpty<IotaAddress> {
1910        let mut signers = nonempty![self.sender];
1911        if self.gas_owner() != self.sender {
1912            signers.push(self.gas_owner());
1913        }
1914        signers
1915    }
1916
1917    fn gas_data(&self) -> &GasData {
1918        &self.gas_data
1919    }
1920
1921    fn gas_owner(&self) -> IotaAddress {
1922        self.gas_data.owner
1923    }
1924
1925    fn gas(&self) -> &[ObjectRef] {
1926        &self.gas_data.payment
1927    }
1928
1929    fn gas_price(&self) -> u64 {
1930        self.gas_data.price
1931    }
1932
1933    fn gas_budget(&self) -> u64 {
1934        self.gas_data.budget
1935    }
1936
1937    fn expiration(&self) -> &TransactionExpiration {
1938        &self.expiration
1939    }
1940
1941    fn contains_shared_object(&self) -> bool {
1942        self.kind.shared_input_objects().next().is_some()
1943    }
1944
1945    fn shared_input_objects(&self) -> Vec<SharedInputObject> {
1946        self.kind.shared_input_objects().collect()
1947    }
1948
1949    fn move_calls(&self) -> Vec<(&ObjectID, &IdentStr, &IdentStr)> {
1950        self.kind.move_calls()
1951    }
1952
1953    fn input_objects(&self) -> UserInputResult<Vec<InputObjectKind>> {
1954        let mut inputs = self.kind.input_objects()?;
1955
1956        if !self.kind.is_system_tx() {
1957            inputs.extend(
1958                self.gas()
1959                    .iter()
1960                    .map(|obj_ref| InputObjectKind::ImmOrOwnedMoveObject(*obj_ref)),
1961            );
1962        }
1963        Ok(inputs)
1964    }
1965
1966    fn receiving_objects(&self) -> Vec<ObjectRef> {
1967        self.kind.receiving_objects()
1968    }
1969
1970    fn validity_check(&self, config: &ProtocolConfig) -> UserInputResult {
1971        fp_ensure!(!self.gas().is_empty(), UserInputError::MissingGasPayment);
1972        fp_ensure!(
1973            self.gas().len() < config.max_gas_payment_objects() as usize,
1974            UserInputError::SizeLimitExceeded {
1975                limit: "maximum number of gas payment objects".to_string(),
1976                value: config.max_gas_payment_objects().to_string()
1977            }
1978        );
1979        self.validity_check_no_gas_check(config)
1980    }
1981
1982    // Keep all the logic for validity here, we need this for dry run where the gas
1983    // may not be provided and created "on the fly"
1984    fn validity_check_no_gas_check(&self, config: &ProtocolConfig) -> UserInputResult {
1985        self.kind().validity_check(config)?;
1986        self.check_sponsorship()
1987    }
1988
1989    /// Check if the transaction is sponsored (namely gas owner != sender)
1990    fn is_sponsored_tx(&self) -> bool {
1991        self.gas_owner() != self.sender
1992    }
1993
1994    /// Check if the transaction is compliant with sponsorship.
1995    fn check_sponsorship(&self) -> UserInputResult {
1996        // Not a sponsored transaction, nothing to check
1997        if self.gas_owner() == self.sender() {
1998            return Ok(());
1999        }
2000        if matches!(&self.kind, TransactionKind::ProgrammableTransaction(_)) {
2001            return Ok(());
2002        }
2003        Err(UserInputError::UnsupportedSponsoredTransactionKind)
2004    }
2005
2006    fn is_end_of_epoch_tx(&self) -> bool {
2007        matches!(self.kind, TransactionKind::EndOfEpochTransaction(_))
2008    }
2009
2010    fn is_system_tx(&self) -> bool {
2011        self.kind.is_system_tx()
2012    }
2013
2014    fn is_genesis_tx(&self) -> bool {
2015        matches!(self.kind, TransactionKind::Genesis(_))
2016    }
2017
2018    fn sender_mut_for_testing(&mut self) -> &mut IotaAddress {
2019        &mut self.sender
2020    }
2021
2022    fn gas_data_mut(&mut self) -> &mut GasData {
2023        &mut self.gas_data
2024    }
2025
2026    fn expiration_mut_for_testing(&mut self) -> &mut TransactionExpiration {
2027        &mut self.expiration
2028    }
2029}
2030
2031impl TransactionDataV1 {}
2032
2033#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
2034pub struct SenderSignedData(SizeOneVec<SenderSignedTransaction>);
2035
2036#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2037pub struct SenderSignedTransaction {
2038    pub intent_message: IntentMessage<TransactionData>,
2039    /// A list of signatures signed by all transaction participants.
2040    /// 1. non participant signature must not be present.
2041    /// 2. signature order does not matter.
2042    pub tx_signatures: Vec<GenericSignature>,
2043}
2044
2045impl Serialize for SenderSignedTransaction {
2046    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
2047    where
2048        S: serde::Serializer,
2049    {
2050        #[derive(Serialize)]
2051        #[serde(rename = "SenderSignedTransaction")]
2052        struct SignedTxn<'a> {
2053            intent_message: &'a IntentMessage<TransactionData>,
2054            tx_signatures: &'a Vec<GenericSignature>,
2055        }
2056
2057        if self.intent_message().intent != Intent::iota_transaction() {
2058            return Err(serde::ser::Error::custom("invalid Intent for Transaction"));
2059        }
2060
2061        let txn = SignedTxn {
2062            intent_message: self.intent_message(),
2063            tx_signatures: &self.tx_signatures,
2064        };
2065        txn.serialize(serializer)
2066    }
2067}
2068
2069impl<'de> Deserialize<'de> for SenderSignedTransaction {
2070    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2071    where
2072        D: serde::Deserializer<'de>,
2073    {
2074        #[derive(Deserialize)]
2075        #[serde(rename = "SenderSignedTransaction")]
2076        struct SignedTxn {
2077            intent_message: IntentMessage<TransactionData>,
2078            tx_signatures: Vec<GenericSignature>,
2079        }
2080
2081        let SignedTxn {
2082            intent_message,
2083            tx_signatures,
2084        } = Deserialize::deserialize(deserializer)?;
2085
2086        if intent_message.intent != Intent::iota_transaction() {
2087            return Err(serde::de::Error::custom("invalid Intent for Transaction"));
2088        }
2089
2090        Ok(Self {
2091            intent_message,
2092            tx_signatures,
2093        })
2094    }
2095}
2096
2097impl SenderSignedTransaction {
2098    pub(crate) fn get_signer_sig_mapping(
2099        &self,
2100    ) -> IotaResult<BTreeMap<IotaAddress, &GenericSignature>> {
2101        let mut mapping = BTreeMap::new();
2102        for sig in &self.tx_signatures {
2103            let address = sig.try_into()?;
2104            mapping.insert(address, sig);
2105        }
2106        Ok(mapping)
2107    }
2108
2109    pub fn intent_message(&self) -> &IntentMessage<TransactionData> {
2110        &self.intent_message
2111    }
2112}
2113
2114impl SenderSignedData {
2115    pub fn new(tx_data: TransactionData, tx_signatures: Vec<GenericSignature>) -> Self {
2116        Self(SizeOneVec::new(SenderSignedTransaction {
2117            intent_message: IntentMessage::new(Intent::iota_transaction(), tx_data),
2118            tx_signatures,
2119        }))
2120    }
2121
2122    pub fn new_from_sender_signature(tx_data: TransactionData, tx_signature: Signature) -> Self {
2123        Self(SizeOneVec::new(SenderSignedTransaction {
2124            intent_message: IntentMessage::new(Intent::iota_transaction(), tx_data),
2125            tx_signatures: vec![tx_signature.into()],
2126        }))
2127    }
2128
2129    pub fn inner(&self) -> &SenderSignedTransaction {
2130        self.0.element()
2131    }
2132
2133    pub fn into_inner(self) -> SenderSignedTransaction {
2134        self.0.into_inner()
2135    }
2136
2137    pub fn inner_mut(&mut self) -> &mut SenderSignedTransaction {
2138        self.0.element_mut()
2139    }
2140
2141    // This function does not check validity of the signature
2142    // or perform any de-dup checks.
2143    pub fn add_signature(&mut self, new_signature: Signature) {
2144        self.inner_mut().tx_signatures.push(new_signature.into());
2145    }
2146
2147    pub(crate) fn get_signer_sig_mapping(
2148        &self,
2149    ) -> IotaResult<BTreeMap<IotaAddress, &GenericSignature>> {
2150        self.inner().get_signer_sig_mapping()
2151    }
2152
2153    pub fn transaction_data(&self) -> &TransactionData {
2154        &self.intent_message().value
2155    }
2156
2157    pub fn intent_message(&self) -> &IntentMessage<TransactionData> {
2158        self.inner().intent_message()
2159    }
2160
2161    pub fn tx_signatures(&self) -> &[GenericSignature] {
2162        &self.inner().tx_signatures
2163    }
2164
2165    pub fn has_zklogin_sig(&self) -> bool {
2166        self.tx_signatures().iter().any(|sig| sig.is_zklogin())
2167    }
2168
2169    pub fn has_upgraded_multisig(&self) -> bool {
2170        self.tx_signatures()
2171            .iter()
2172            .any(|sig| sig.is_upgraded_multisig())
2173    }
2174
2175    #[cfg(test)]
2176    pub fn intent_message_mut_for_testing(&mut self) -> &mut IntentMessage<TransactionData> {
2177        &mut self.inner_mut().intent_message
2178    }
2179
2180    // used cross-crate, so cannot be #[cfg(test)]
2181    pub fn tx_signatures_mut_for_testing(&mut self) -> &mut Vec<GenericSignature> {
2182        &mut self.inner_mut().tx_signatures
2183    }
2184
2185    pub fn full_message_digest(&self) -> SenderSignedDataDigest {
2186        let mut digest = DefaultHash::default();
2187        bcs::serialize_into(&mut digest, self).expect("serialization should not fail");
2188        let hash = digest.finalize();
2189        SenderSignedDataDigest::new(hash.into())
2190    }
2191
2192    pub fn serialized_size(&self) -> IotaResult<usize> {
2193        bcs::serialized_size(self).map_err(|e| IotaError::TransactionSerialization {
2194            error: e.to_string(),
2195        })
2196    }
2197
2198    fn check_user_signature_protocol_compatibility(&self, config: &ProtocolConfig) -> IotaResult {
2199        for sig in &self.inner().tx_signatures {
2200            match sig {
2201                GenericSignature::ZkLoginAuthenticator(_) => {
2202                    if !config.zklogin_auth() {
2203                        return Err(IotaError::UserInput {
2204                            error: UserInputError::Unsupported(
2205                                "zklogin is not enabled on this network".to_string(),
2206                            ),
2207                        });
2208                    }
2209                }
2210                GenericSignature::PasskeyAuthenticator(_) => {
2211                    if !config.passkey_auth() {
2212                        return Err(IotaError::UserInput {
2213                            error: UserInputError::Unsupported(
2214                                "passkey is not enabled on this network".to_string(),
2215                            ),
2216                        });
2217                    }
2218                }
2219                GenericSignature::Signature(_) | GenericSignature::MultiSig(_) => (),
2220            }
2221        }
2222
2223        Ok(())
2224    }
2225
2226    /// Validate untrusted user transaction, including its size, input count,
2227    /// command count, etc.
2228    /// Returns the certificate serialised bytes size.
2229    pub fn validity_check(
2230        &self,
2231        config: &ProtocolConfig,
2232        epoch: EpochId,
2233    ) -> Result<usize, IotaError> {
2234        // Check that the features used by the user signatures are enabled on the
2235        // network.
2236        self.check_user_signature_protocol_compatibility(config)?;
2237
2238        // CRITICAL!!
2239        // Users cannot send system transactions.
2240        let tx_data = &self.transaction_data();
2241        fp_ensure!(
2242            !tx_data.is_system_tx(),
2243            IotaError::UserInput {
2244                error: UserInputError::Unsupported(
2245                    "SenderSignedData must not contain system transaction".to_string()
2246                )
2247            }
2248        );
2249
2250        // Checks to see if the transaction has expired
2251        if match &tx_data.expiration() {
2252            TransactionExpiration::None => false,
2253            TransactionExpiration::Epoch(exp_poch) => *exp_poch < epoch,
2254        } {
2255            return Err(IotaError::TransactionExpired);
2256        }
2257
2258        // Enforce overall transaction size limit.
2259        let tx_size = self.serialized_size()?;
2260        let max_tx_size_bytes = config.max_tx_size_bytes();
2261        fp_ensure!(
2262            tx_size as u64 <= max_tx_size_bytes,
2263            IotaError::UserInput {
2264                error: UserInputError::SizeLimitExceeded {
2265                    limit: format!(
2266                        "serialized transaction size exceeded maximum of {max_tx_size_bytes}"
2267                    ),
2268                    value: tx_size.to_string(),
2269                }
2270            }
2271        );
2272
2273        tx_data
2274            .validity_check(config)
2275            .map_err(Into::<IotaError>::into)?;
2276
2277        Ok(tx_size)
2278    }
2279}
2280
2281impl Message for SenderSignedData {
2282    type DigestType = TransactionDigest;
2283    const SCOPE: IntentScope = IntentScope::SenderSignedTransaction;
2284
2285    /// Computes the tx digest that encodes the Rust type prefix from Signable
2286    /// trait.
2287    fn digest(&self) -> Self::DigestType {
2288        self.intent_message().value.digest()
2289    }
2290}
2291
2292impl<S> Envelope<SenderSignedData, S> {
2293    pub fn sender_address(&self) -> IotaAddress {
2294        self.data().intent_message().value.sender()
2295    }
2296
2297    pub fn gas(&self) -> &[ObjectRef] {
2298        self.data().intent_message().value.gas()
2299    }
2300
2301    pub fn contains_shared_object(&self) -> bool {
2302        self.shared_input_objects().next().is_some()
2303    }
2304
2305    pub fn shared_input_objects(&self) -> impl Iterator<Item = SharedInputObject> + '_ {
2306        self.data()
2307            .inner()
2308            .intent_message
2309            .value
2310            .shared_input_objects()
2311            .into_iter()
2312    }
2313
2314    // Returns the primary key for this transaction.
2315    pub fn key(&self) -> TransactionKey {
2316        match &self.data().intent_message().value.kind() {
2317            TransactionKind::RandomnessStateUpdate(rsu) => {
2318                TransactionKey::RandomnessRound(rsu.epoch, rsu.randomness_round)
2319            }
2320            _ => TransactionKey::Digest(*self.digest()),
2321        }
2322    }
2323
2324    // Returns non-Digest keys that could be used to refer to this transaction.
2325    //
2326    // At the moment this returns a single Option for efficiency, but if more key
2327    // types are added, the return type could change to Vec<TransactionKey>.
2328    pub fn non_digest_key(&self) -> Option<TransactionKey> {
2329        match &self.data().intent_message().value.kind() {
2330            TransactionKind::RandomnessStateUpdate(rsu) => Some(TransactionKey::RandomnessRound(
2331                rsu.epoch,
2332                rsu.randomness_round,
2333            )),
2334            _ => None,
2335        }
2336    }
2337
2338    pub fn is_system_tx(&self) -> bool {
2339        self.data().intent_message().value.is_system_tx()
2340    }
2341
2342    pub fn is_sponsored_tx(&self) -> bool {
2343        self.data().intent_message().value.is_sponsored_tx()
2344    }
2345}
2346
2347impl Transaction {
2348    pub fn from_data_and_signer(
2349        data: TransactionData,
2350        signers: Vec<&dyn Signer<Signature>>,
2351    ) -> Self {
2352        let signatures = {
2353            let intent_msg = IntentMessage::new(Intent::iota_transaction(), &data);
2354            signers
2355                .into_iter()
2356                .map(|s| Signature::new_secure(&intent_msg, s))
2357                .collect()
2358        };
2359        Self::from_data(data, signatures)
2360    }
2361
2362    // TODO: Rename this function and above to make it clearer.
2363    pub fn from_data(data: TransactionData, signatures: Vec<Signature>) -> Self {
2364        Self::from_generic_sig_data(data, signatures.into_iter().map(|s| s.into()).collect())
2365    }
2366
2367    pub fn signature_from_signer(
2368        data: TransactionData,
2369        intent: Intent,
2370        signer: &dyn Signer<Signature>,
2371    ) -> Signature {
2372        let intent_msg = IntentMessage::new(intent, data);
2373        Signature::new_secure(&intent_msg, signer)
2374    }
2375
2376    pub fn from_generic_sig_data(data: TransactionData, signatures: Vec<GenericSignature>) -> Self {
2377        Self::new(SenderSignedData::new(data, signatures))
2378    }
2379
2380    /// Returns the Base64 encoded tx_bytes
2381    /// and a list of Base64 encoded [enum GenericSignature].
2382    pub fn to_tx_bytes_and_signatures(&self) -> (Base64, Vec<Base64>) {
2383        (
2384            Base64::from_bytes(&bcs::to_bytes(&self.data().intent_message().value).unwrap()),
2385            self.data()
2386                .inner()
2387                .tx_signatures
2388                .iter()
2389                .map(|s| Base64::from_bytes(s.as_ref()))
2390                .collect(),
2391        )
2392    }
2393}
2394
2395impl VerifiedTransaction {
2396    pub fn new_genesis_transaction(objects: Vec<GenesisObject>, events: Vec<Event>) -> Self {
2397        GenesisTransaction { objects, events }
2398            .pipe(TransactionKind::Genesis)
2399            .pipe(Self::new_system_transaction)
2400    }
2401
2402    pub fn new_consensus_commit_prologue_v1(
2403        epoch: u64,
2404        round: u64,
2405        commit_timestamp_ms: CheckpointTimestamp,
2406        consensus_commit_digest: ConsensusCommitDigest,
2407        cancelled_txn_version_assignment: Vec<(TransactionDigest, Vec<(ObjectID, SequenceNumber)>)>,
2408    ) -> Self {
2409        ConsensusCommitPrologueV1 {
2410            epoch,
2411            round,
2412            // sub_dag_index is reserved for when we have multi commits per round.
2413            sub_dag_index: None,
2414            commit_timestamp_ms,
2415            consensus_commit_digest,
2416            consensus_determined_version_assignments:
2417                ConsensusDeterminedVersionAssignments::CancelledTransactions(
2418                    cancelled_txn_version_assignment,
2419                ),
2420        }
2421        .pipe(TransactionKind::ConsensusCommitPrologueV1)
2422        .pipe(Self::new_system_transaction)
2423    }
2424
2425    pub fn new_authenticator_state_update(
2426        epoch: u64,
2427        round: u64,
2428        new_active_jwks: Vec<ActiveJwk>,
2429        authenticator_obj_initial_shared_version: SequenceNumber,
2430    ) -> Self {
2431        AuthenticatorStateUpdateV1 {
2432            epoch,
2433            round,
2434            new_active_jwks,
2435            authenticator_obj_initial_shared_version,
2436        }
2437        .pipe(TransactionKind::AuthenticatorStateUpdateV1)
2438        .pipe(Self::new_system_transaction)
2439    }
2440
2441    pub fn new_randomness_state_update(
2442        epoch: u64,
2443        randomness_round: RandomnessRound,
2444        random_bytes: Vec<u8>,
2445        randomness_obj_initial_shared_version: SequenceNumber,
2446    ) -> Self {
2447        RandomnessStateUpdate {
2448            epoch,
2449            randomness_round,
2450            random_bytes,
2451            randomness_obj_initial_shared_version,
2452        }
2453        .pipe(TransactionKind::RandomnessStateUpdate)
2454        .pipe(Self::new_system_transaction)
2455    }
2456
2457    pub fn new_end_of_epoch_transaction(txns: Vec<EndOfEpochTransactionKind>) -> Self {
2458        TransactionKind::EndOfEpochTransaction(txns).pipe(Self::new_system_transaction)
2459    }
2460
2461    fn new_system_transaction(system_transaction: TransactionKind) -> Self {
2462        system_transaction
2463            .pipe(TransactionData::new_system_transaction)
2464            .pipe(|data| {
2465                SenderSignedData::new_from_sender_signature(
2466                    data,
2467                    Ed25519IotaSignature::from_bytes(&[0; Ed25519IotaSignature::LENGTH])
2468                        .unwrap()
2469                        .into(),
2470                )
2471            })
2472            .pipe(Transaction::new)
2473            .pipe(Self::new_from_verified)
2474    }
2475}
2476
2477impl VerifiedSignedTransaction {
2478    /// Use signing key to create a signed object.
2479    pub fn new(
2480        epoch: EpochId,
2481        transaction: VerifiedTransaction,
2482        authority: AuthorityName,
2483        secret: &dyn Signer<AuthoritySignature>,
2484    ) -> Self {
2485        Self::new_from_verified(SignedTransaction::new(
2486            epoch,
2487            transaction.into_inner().into_data(),
2488            secret,
2489            authority,
2490        ))
2491    }
2492}
2493
2494/// A transaction that is signed by a sender but not yet by an authority.
2495pub type Transaction = Envelope<SenderSignedData, EmptySignInfo>;
2496pub type VerifiedTransaction = VerifiedEnvelope<SenderSignedData, EmptySignInfo>;
2497pub type TrustedTransaction = TrustedEnvelope<SenderSignedData, EmptySignInfo>;
2498
2499/// A transaction that is signed by a sender and also by an authority.
2500pub type SignedTransaction = Envelope<SenderSignedData, AuthoritySignInfo>;
2501pub type VerifiedSignedTransaction = VerifiedEnvelope<SenderSignedData, AuthoritySignInfo>;
2502
2503impl Transaction {
2504    pub fn verify_signature_for_testing(
2505        &self,
2506        current_epoch: EpochId,
2507        verify_params: &VerifyParams,
2508    ) -> IotaResult {
2509        verify_sender_signed_data_message_signatures(
2510            self.data(),
2511            current_epoch,
2512            verify_params,
2513            Arc::new(VerifiedDigestCache::new_empty()),
2514        )
2515    }
2516
2517    pub fn try_into_verified_for_testing(
2518        self,
2519        current_epoch: EpochId,
2520        verify_params: &VerifyParams,
2521    ) -> IotaResult<VerifiedTransaction> {
2522        self.verify_signature_for_testing(current_epoch, verify_params)?;
2523        Ok(VerifiedTransaction::new_from_verified(self))
2524    }
2525}
2526
2527impl SignedTransaction {
2528    pub fn verify_signatures_authenticated_for_testing(
2529        &self,
2530        committee: &Committee,
2531        verify_params: &VerifyParams,
2532    ) -> IotaResult {
2533        verify_sender_signed_data_message_signatures(
2534            self.data(),
2535            committee.epoch(),
2536            verify_params,
2537            Arc::new(VerifiedDigestCache::new_empty()),
2538        )?;
2539
2540        self.auth_sig().verify_secure(
2541            self.data(),
2542            Intent::iota_app(IntentScope::SenderSignedTransaction),
2543            committee,
2544        )
2545    }
2546
2547    pub fn try_into_verified_for_testing(
2548        self,
2549        committee: &Committee,
2550        verify_params: &VerifyParams,
2551    ) -> IotaResult<VerifiedSignedTransaction> {
2552        self.verify_signatures_authenticated_for_testing(committee, verify_params)?;
2553        Ok(VerifiedSignedTransaction::new_from_verified(self))
2554    }
2555}
2556
2557pub type CertifiedTransaction = Envelope<SenderSignedData, AuthorityStrongQuorumSignInfo>;
2558
2559impl CertifiedTransaction {
2560    pub fn certificate_digest(&self) -> CertificateDigest {
2561        let mut digest = DefaultHash::default();
2562        bcs::serialize_into(&mut digest, self).expect("serialization should not fail");
2563        let hash = digest.finalize();
2564        CertificateDigest::new(hash.into())
2565    }
2566
2567    pub fn gas_price(&self) -> u64 {
2568        self.data().transaction_data().gas_price()
2569    }
2570
2571    // TODO: Eventually we should remove all calls to verify_signature
2572    // and make sure they all call verify to avoid repeated verifications.
2573    pub fn verify_signatures_authenticated(
2574        &self,
2575        committee: &Committee,
2576        verify_params: &VerifyParams,
2577        zklogin_inputs_cache: Arc<VerifiedDigestCache<ZKLoginInputsDigest>>,
2578    ) -> IotaResult {
2579        verify_sender_signed_data_message_signatures(
2580            self.data(),
2581            committee.epoch(),
2582            verify_params,
2583            zklogin_inputs_cache,
2584        )?;
2585        self.auth_sig().verify_secure(
2586            self.data(),
2587            Intent::iota_app(IntentScope::SenderSignedTransaction),
2588            committee,
2589        )
2590    }
2591
2592    pub fn try_into_verified_for_testing(
2593        self,
2594        committee: &Committee,
2595        verify_params: &VerifyParams,
2596    ) -> IotaResult<VerifiedCertificate> {
2597        self.verify_signatures_authenticated(
2598            committee,
2599            verify_params,
2600            Arc::new(VerifiedDigestCache::new_empty()),
2601        )?;
2602        Ok(VerifiedCertificate::new_from_verified(self))
2603    }
2604
2605    pub fn verify_committee_sigs_only(&self, committee: &Committee) -> IotaResult {
2606        self.auth_sig().verify_secure(
2607            self.data(),
2608            Intent::iota_app(IntentScope::SenderSignedTransaction),
2609            committee,
2610        )
2611    }
2612}
2613
2614pub type VerifiedCertificate = VerifiedEnvelope<SenderSignedData, AuthorityStrongQuorumSignInfo>;
2615pub type TrustedCertificate = TrustedEnvelope<SenderSignedData, AuthorityStrongQuorumSignInfo>;
2616
2617#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize, PartialOrd, Ord, Hash)]
2618pub enum InputObjectKind {
2619    // A Move package, must be immutable.
2620    MovePackage(ObjectID),
2621    // A Move object, either immutable, or owned mutable.
2622    ImmOrOwnedMoveObject(ObjectRef),
2623    // A Move object that's shared and mutable.
2624    SharedMoveObject {
2625        id: ObjectID,
2626        initial_shared_version: SequenceNumber,
2627        mutable: bool,
2628    },
2629}
2630
2631impl InputObjectKind {
2632    pub fn object_id(&self) -> ObjectID {
2633        match self {
2634            Self::MovePackage(id) => *id,
2635            Self::ImmOrOwnedMoveObject((id, _, _)) => *id,
2636            Self::SharedMoveObject { id, .. } => *id,
2637        }
2638    }
2639
2640    pub fn version(&self) -> Option<SequenceNumber> {
2641        match self {
2642            Self::MovePackage(..) => None,
2643            Self::ImmOrOwnedMoveObject((_, version, _)) => Some(*version),
2644            Self::SharedMoveObject { .. } => None,
2645        }
2646    }
2647
2648    pub fn object_not_found_error(&self) -> UserInputError {
2649        match *self {
2650            Self::MovePackage(package_id) => {
2651                UserInputError::DependentPackageNotFound { package_id }
2652            }
2653            Self::ImmOrOwnedMoveObject((object_id, version, _)) => UserInputError::ObjectNotFound {
2654                object_id,
2655                version: Some(version),
2656            },
2657            Self::SharedMoveObject { id, .. } => UserInputError::ObjectNotFound {
2658                object_id: id,
2659                version: None,
2660            },
2661        }
2662    }
2663
2664    pub fn is_shared_object(&self) -> bool {
2665        matches!(self, Self::SharedMoveObject { .. })
2666    }
2667
2668    pub fn is_mutable(&self) -> bool {
2669        match self {
2670            Self::MovePackage(..) => false,
2671            Self::ImmOrOwnedMoveObject((_, _, _)) => true,
2672            Self::SharedMoveObject { mutable, .. } => *mutable,
2673        }
2674    }
2675}
2676
2677/// The result of reading an object for execution. Because shared objects may be
2678/// deleted, one possible result of reading a shared object is that
2679/// ObjectReadResultKind::Deleted is returned.
2680#[derive(Clone, Debug)]
2681pub struct ObjectReadResult {
2682    pub input_object_kind: InputObjectKind,
2683    pub object: ObjectReadResultKind,
2684}
2685
2686#[derive(Clone)]
2687pub enum ObjectReadResultKind {
2688    Object(Object),
2689    // The version of the object that the transaction intended to read, and the digest of the tx
2690    // that deleted it.
2691    DeletedSharedObject(SequenceNumber, TransactionDigest),
2692    // A shared object in a cancelled transaction. The sequence number embeds cancellation reason.
2693    CancelledTransactionSharedObject(SequenceNumber),
2694}
2695
2696impl std::fmt::Debug for ObjectReadResultKind {
2697    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2698        match self {
2699            ObjectReadResultKind::Object(obj) => {
2700                write!(f, "Object({:?})", obj.compute_object_reference())
2701            }
2702            ObjectReadResultKind::DeletedSharedObject(seq, digest) => {
2703                write!(f, "DeletedSharedObject({}, {:?})", seq, digest)
2704            }
2705            ObjectReadResultKind::CancelledTransactionSharedObject(seq) => {
2706                write!(f, "CancelledTransactionSharedObject({})", seq)
2707            }
2708        }
2709    }
2710}
2711
2712impl From<Object> for ObjectReadResultKind {
2713    fn from(object: Object) -> Self {
2714        Self::Object(object)
2715    }
2716}
2717
2718impl ObjectReadResult {
2719    pub fn new(input_object_kind: InputObjectKind, object: ObjectReadResultKind) -> Self {
2720        if let (
2721            InputObjectKind::ImmOrOwnedMoveObject(_),
2722            ObjectReadResultKind::DeletedSharedObject(_, _),
2723        ) = (&input_object_kind, &object)
2724        {
2725            panic!("only shared objects can be DeletedSharedObject");
2726        }
2727
2728        if let (
2729            InputObjectKind::ImmOrOwnedMoveObject(_),
2730            ObjectReadResultKind::CancelledTransactionSharedObject(_),
2731        ) = (&input_object_kind, &object)
2732        {
2733            panic!("only shared objects can be CancelledTransactionSharedObject");
2734        }
2735
2736        Self {
2737            input_object_kind,
2738            object,
2739        }
2740    }
2741
2742    pub fn id(&self) -> ObjectID {
2743        self.input_object_kind.object_id()
2744    }
2745
2746    pub fn as_object(&self) -> Option<&Object> {
2747        match &self.object {
2748            ObjectReadResultKind::Object(object) => Some(object),
2749            ObjectReadResultKind::DeletedSharedObject(_, _) => None,
2750            ObjectReadResultKind::CancelledTransactionSharedObject(_) => None,
2751        }
2752    }
2753
2754    pub fn new_from_gas_object(gas: &Object) -> Self {
2755        let objref = gas.compute_object_reference();
2756        Self {
2757            input_object_kind: InputObjectKind::ImmOrOwnedMoveObject(objref),
2758            object: ObjectReadResultKind::Object(gas.clone()),
2759        }
2760    }
2761
2762    pub fn is_mutable(&self) -> bool {
2763        match (&self.input_object_kind, &self.object) {
2764            (InputObjectKind::MovePackage(_), _) => false,
2765            (InputObjectKind::ImmOrOwnedMoveObject(_), ObjectReadResultKind::Object(object)) => {
2766                !object.is_immutable()
2767            }
2768            (
2769                InputObjectKind::ImmOrOwnedMoveObject(_),
2770                ObjectReadResultKind::DeletedSharedObject(_, _),
2771            ) => unreachable!(),
2772            (
2773                InputObjectKind::ImmOrOwnedMoveObject(_),
2774                ObjectReadResultKind::CancelledTransactionSharedObject(_),
2775            ) => unreachable!(),
2776            (InputObjectKind::SharedMoveObject { mutable, .. }, _) => *mutable,
2777        }
2778    }
2779
2780    pub fn is_shared_object(&self) -> bool {
2781        self.input_object_kind.is_shared_object()
2782    }
2783
2784    pub fn is_deleted_shared_object(&self) -> bool {
2785        self.deletion_info().is_some()
2786    }
2787
2788    pub fn deletion_info(&self) -> Option<(SequenceNumber, TransactionDigest)> {
2789        match &self.object {
2790            ObjectReadResultKind::DeletedSharedObject(v, tx) => Some((*v, *tx)),
2791            _ => None,
2792        }
2793    }
2794
2795    /// Return the object ref iff the object is an owned object (i.e. not
2796    /// shared, not immutable).
2797    pub fn get_owned_objref(&self) -> Option<ObjectRef> {
2798        match (&self.input_object_kind, &self.object) {
2799            (InputObjectKind::MovePackage(_), _) => None,
2800            (
2801                InputObjectKind::ImmOrOwnedMoveObject(objref),
2802                ObjectReadResultKind::Object(object),
2803            ) => {
2804                if object.is_immutable() {
2805                    None
2806                } else {
2807                    Some(*objref)
2808                }
2809            }
2810            (
2811                InputObjectKind::ImmOrOwnedMoveObject(_),
2812                ObjectReadResultKind::DeletedSharedObject(_, _),
2813            ) => unreachable!(),
2814            (
2815                InputObjectKind::ImmOrOwnedMoveObject(_),
2816                ObjectReadResultKind::CancelledTransactionSharedObject(_),
2817            ) => unreachable!(),
2818            (InputObjectKind::SharedMoveObject { .. }, _) => None,
2819        }
2820    }
2821
2822    pub fn is_owned(&self) -> bool {
2823        self.get_owned_objref().is_some()
2824    }
2825
2826    pub fn to_shared_input(&self) -> Option<SharedInput> {
2827        match self.input_object_kind {
2828            InputObjectKind::MovePackage(_) => None,
2829            InputObjectKind::ImmOrOwnedMoveObject(_) => None,
2830            InputObjectKind::SharedMoveObject { id, mutable, .. } => Some(match &self.object {
2831                ObjectReadResultKind::Object(obj) => {
2832                    SharedInput::Existing(obj.compute_object_reference())
2833                }
2834                ObjectReadResultKind::DeletedSharedObject(seq, digest) => {
2835                    SharedInput::Deleted((id, *seq, mutable, *digest))
2836                }
2837                ObjectReadResultKind::CancelledTransactionSharedObject(seq) => {
2838                    SharedInput::Cancelled((id, *seq))
2839                }
2840            }),
2841        }
2842    }
2843
2844    pub fn get_previous_transaction(&self) -> Option<TransactionDigest> {
2845        match &self.object {
2846            ObjectReadResultKind::Object(obj) => Some(obj.previous_transaction),
2847            ObjectReadResultKind::DeletedSharedObject(_, digest) => Some(*digest),
2848            ObjectReadResultKind::CancelledTransactionSharedObject(_) => None,
2849        }
2850    }
2851}
2852
2853#[derive(Clone)]
2854pub struct InputObjects {
2855    objects: Vec<ObjectReadResult>,
2856}
2857
2858impl std::fmt::Debug for InputObjects {
2859    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2860        f.debug_list().entries(self.objects.iter()).finish()
2861    }
2862}
2863
2864// An InputObjects new-type that has been verified by iota-transaction-checks,
2865// and can be safely passed to execution.
2866pub struct CheckedInputObjects(InputObjects);
2867
2868// DO NOT CALL outside of iota-transaction-checks, genesis, or replay.
2869//
2870// CheckedInputObjects should really be defined in iota-transaction-checks so
2871// that we can make public construction impossible. But we can't do that because
2872// it would result in circular dependencies.
2873impl CheckedInputObjects {
2874    // Only called by iota-transaction-checks.
2875    pub fn new_with_checked_transaction_inputs(inputs: InputObjects) -> Self {
2876        Self(inputs)
2877    }
2878
2879    // Only called when building the genesis transaction
2880    pub fn new_for_genesis(input_objects: Vec<ObjectReadResult>) -> Self {
2881        Self(InputObjects::new(input_objects))
2882    }
2883
2884    // Only called from the replay tool.
2885    pub fn new_for_replay(input_objects: InputObjects) -> Self {
2886        Self(input_objects)
2887    }
2888
2889    pub fn inner(&self) -> &InputObjects {
2890        &self.0
2891    }
2892
2893    pub fn into_inner(self) -> InputObjects {
2894        self.0
2895    }
2896}
2897
2898impl From<Vec<ObjectReadResult>> for InputObjects {
2899    fn from(objects: Vec<ObjectReadResult>) -> Self {
2900        Self::new(objects)
2901    }
2902}
2903
2904impl InputObjects {
2905    pub fn new(objects: Vec<ObjectReadResult>) -> Self {
2906        Self { objects }
2907    }
2908
2909    pub fn len(&self) -> usize {
2910        self.objects.len()
2911    }
2912
2913    pub fn is_empty(&self) -> bool {
2914        self.objects.is_empty()
2915    }
2916
2917    pub fn contains_deleted_objects(&self) -> bool {
2918        self.objects
2919            .iter()
2920            .any(|obj| obj.is_deleted_shared_object())
2921    }
2922
2923    // Returns IDs of objects responsible for a transaction being cancelled, and the
2924    // corresponding reason for cancellation.
2925    pub fn get_cancelled_objects(&self) -> Option<(Vec<ObjectID>, SequenceNumber)> {
2926        let mut contains_cancelled = false;
2927        let mut cancel_reason = None;
2928        let mut cancelled_objects = Vec::new();
2929        for obj in &self.objects {
2930            if let ObjectReadResultKind::CancelledTransactionSharedObject(version) = obj.object {
2931                contains_cancelled = true;
2932                if version == SequenceNumber::CONGESTED
2933                    || version == SequenceNumber::RANDOMNESS_UNAVAILABLE
2934                {
2935                    // Verify we don't have multiple cancellation reasons.
2936                    assert!(cancel_reason.is_none() || cancel_reason == Some(version));
2937                    cancel_reason = Some(version);
2938                    cancelled_objects.push(obj.id());
2939                }
2940            }
2941        }
2942
2943        if !cancelled_objects.is_empty() {
2944            Some((
2945                cancelled_objects,
2946                cancel_reason
2947                    .expect("there should be a cancel reason if there are cancelled objects"),
2948            ))
2949        } else {
2950            assert!(!contains_cancelled);
2951            None
2952        }
2953    }
2954
2955    pub fn filter_owned_objects(&self) -> Vec<ObjectRef> {
2956        let owned_objects: Vec<_> = self
2957            .objects
2958            .iter()
2959            .filter_map(|obj| obj.get_owned_objref())
2960            .collect();
2961
2962        trace!(
2963            num_mutable_objects = owned_objects.len(),
2964            "Checked locks and found mutable objects"
2965        );
2966
2967        owned_objects
2968    }
2969
2970    pub fn filter_shared_objects(&self) -> Vec<SharedInput> {
2971        self.objects
2972            .iter()
2973            .filter(|obj| obj.is_shared_object())
2974            .map(|obj| {
2975                obj.to_shared_input()
2976                    .expect("already filtered for shared objects")
2977            })
2978            .collect()
2979    }
2980
2981    pub fn transaction_dependencies(&self) -> BTreeSet<TransactionDigest> {
2982        self.objects
2983            .iter()
2984            .filter_map(|obj| obj.get_previous_transaction())
2985            .collect()
2986    }
2987
2988    pub fn mutable_inputs(&self) -> BTreeMap<ObjectID, (VersionDigest, Owner)> {
2989        self.objects
2990            .iter()
2991            .filter_map(
2992                |ObjectReadResult {
2993                     input_object_kind,
2994                     object,
2995                 }| match (input_object_kind, object) {
2996                    (InputObjectKind::MovePackage(_), _) => None,
2997                    (
2998                        InputObjectKind::ImmOrOwnedMoveObject(object_ref),
2999                        ObjectReadResultKind::Object(object),
3000                    ) => {
3001                        if object.is_immutable() {
3002                            None
3003                        } else {
3004                            Some((object_ref.0, ((object_ref.1, object_ref.2), object.owner)))
3005                        }
3006                    }
3007                    (
3008                        InputObjectKind::ImmOrOwnedMoveObject(_),
3009                        ObjectReadResultKind::DeletedSharedObject(_, _),
3010                    ) => {
3011                        unreachable!()
3012                    }
3013                    (
3014                        InputObjectKind::SharedMoveObject { .. },
3015                        ObjectReadResultKind::DeletedSharedObject(_, _),
3016                    ) => None,
3017                    (
3018                        InputObjectKind::SharedMoveObject { mutable, .. },
3019                        ObjectReadResultKind::Object(object),
3020                    ) => {
3021                        if *mutable {
3022                            let oref = object.compute_object_reference();
3023                            Some((oref.0, ((oref.1, oref.2), object.owner)))
3024                        } else {
3025                            None
3026                        }
3027                    }
3028                    (
3029                        InputObjectKind::ImmOrOwnedMoveObject(_),
3030                        ObjectReadResultKind::CancelledTransactionSharedObject(_),
3031                    ) => {
3032                        unreachable!()
3033                    }
3034                    (
3035                        InputObjectKind::SharedMoveObject { .. },
3036                        ObjectReadResultKind::CancelledTransactionSharedObject(_),
3037                    ) => None,
3038                },
3039            )
3040            .collect()
3041    }
3042
3043    /// The version to set on objects created by the computation that `self` is
3044    /// input to. Guaranteed to be strictly greater than the versions of all
3045    /// input objects and objects received in the transaction.
3046    pub fn lamport_timestamp(&self, receiving_objects: &[ObjectRef]) -> SequenceNumber {
3047        let input_versions = self
3048            .objects
3049            .iter()
3050            .filter_map(|object| match &object.object {
3051                ObjectReadResultKind::Object(object) => {
3052                    object.data.try_as_move().map(MoveObject::version)
3053                }
3054                ObjectReadResultKind::DeletedSharedObject(v, _) => Some(*v),
3055                ObjectReadResultKind::CancelledTransactionSharedObject(_) => None,
3056            })
3057            .chain(receiving_objects.iter().map(|object_ref| object_ref.1));
3058
3059        SequenceNumber::lamport_increment(input_versions)
3060    }
3061
3062    pub fn object_kinds(&self) -> impl Iterator<Item = &InputObjectKind> {
3063        self.objects.iter().map(
3064            |ObjectReadResult {
3065                 input_object_kind, ..
3066             }| input_object_kind,
3067        )
3068    }
3069
3070    pub fn into_object_map(self) -> BTreeMap<ObjectID, Object> {
3071        self.objects
3072            .into_iter()
3073            .filter_map(|o| o.as_object().map(|object| (o.id(), object.clone())))
3074            .collect()
3075    }
3076
3077    pub fn push(&mut self, object: ObjectReadResult) {
3078        self.objects.push(object);
3079    }
3080
3081    pub fn iter(&self) -> impl Iterator<Item = &ObjectReadResult> {
3082        self.objects.iter()
3083    }
3084
3085    pub fn iter_objects(&self) -> impl Iterator<Item = &Object> {
3086        self.objects.iter().filter_map(|o| o.as_object())
3087    }
3088}
3089
3090// Result of attempting to read a receiving object (currently only at signing
3091// time). Because an object may have been previously received and deleted, the
3092// result may be ReceivingObjectReadResultKind::PreviouslyReceivedObject.
3093#[derive(Clone, Debug)]
3094pub enum ReceivingObjectReadResultKind {
3095    Object(Object),
3096    // The object was received by some other transaction, and we were not able to read it
3097    PreviouslyReceivedObject,
3098}
3099
3100impl ReceivingObjectReadResultKind {
3101    pub fn as_object(&self) -> Option<&Object> {
3102        match &self {
3103            Self::Object(object) => Some(object),
3104            Self::PreviouslyReceivedObject => None,
3105        }
3106    }
3107}
3108
3109pub struct ReceivingObjectReadResult {
3110    pub object_ref: ObjectRef,
3111    pub object: ReceivingObjectReadResultKind,
3112}
3113
3114impl ReceivingObjectReadResult {
3115    pub fn new(object_ref: ObjectRef, object: ReceivingObjectReadResultKind) -> Self {
3116        Self { object_ref, object }
3117    }
3118
3119    pub fn is_previously_received(&self) -> bool {
3120        matches!(
3121            self.object,
3122            ReceivingObjectReadResultKind::PreviouslyReceivedObject
3123        )
3124    }
3125}
3126
3127impl From<Object> for ReceivingObjectReadResultKind {
3128    fn from(object: Object) -> Self {
3129        Self::Object(object)
3130    }
3131}
3132
3133pub struct ReceivingObjects {
3134    pub objects: Vec<ReceivingObjectReadResult>,
3135}
3136
3137impl ReceivingObjects {
3138    pub fn iter(&self) -> impl Iterator<Item = &ReceivingObjectReadResult> {
3139        self.objects.iter()
3140    }
3141
3142    pub fn iter_objects(&self) -> impl Iterator<Item = &Object> {
3143        self.objects.iter().filter_map(|o| o.object.as_object())
3144    }
3145}
3146
3147impl From<Vec<ReceivingObjectReadResult>> for ReceivingObjects {
3148    fn from(objects: Vec<ReceivingObjectReadResult>) -> Self {
3149        Self { objects }
3150    }
3151}
3152
3153impl Display for CertifiedTransaction {
3154    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
3155        let mut writer = String::new();
3156        writeln!(writer, "Transaction Hash: {:?}", self.digest())?;
3157        writeln!(
3158            writer,
3159            "Signed Authorities Bitmap : {:?}",
3160            self.auth_sig().signers_map
3161        )?;
3162        write!(writer, "{}", &self.data().intent_message().value.kind())?;
3163        write!(f, "{}", writer)
3164    }
3165}
3166
3167/// TransactionKey uniquely identifies a transaction across all epochs.
3168/// Note that a single transaction may have multiple keys, for example a
3169/// RandomnessStateUpdate could be identified by both `Digest` and
3170/// `RandomnessRound`.
3171#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
3172pub enum TransactionKey {
3173    Digest(TransactionDigest),
3174    RandomnessRound(EpochId, RandomnessRound),
3175}
3176
3177impl TransactionKey {
3178    pub fn unwrap_digest(&self) -> &TransactionDigest {
3179        match self {
3180            TransactionKey::Digest(d) => d,
3181            _ => panic!("called expect_digest on a non-Digest TransactionKey: {self:?}"),
3182        }
3183    }
3184}