radix_transactions/model/v1/
round_update_transaction.rs

1use crate::internal_prelude::*;
2
3/// This is used in the node to increment rounds.
4#[derive(Debug, Clone, Categorize, Encode, Decode, PartialEq, Eq, ScryptoDescribe)]
5pub struct RoundUpdateTransactionV1 {
6    pub proposer_timestamp_ms: i64,
7    pub epoch: Epoch,
8    pub round: Round,
9    pub leader_proposal_history: LeaderProposalHistory,
10}
11
12impl RoundUpdateTransactionV1 {
13    /// Note - we purposefully restrict what the content of a Round Update transaction can do
14    /// so we convert it to instructions at run-time.
15    pub fn create_instructions(&self) -> Vec<InstructionV1> {
16        vec![InstructionV1::CallMethod(CallMethod {
17            address: CONSENSUS_MANAGER.into(),
18            method_name: CONSENSUS_MANAGER_NEXT_ROUND_IDENT.to_string(),
19            args: to_manifest_value(&ConsensusManagerNextRoundInput {
20                round: self.round,
21                proposer_timestamp_ms: self.proposer_timestamp_ms,
22                leader_proposal_history: self.leader_proposal_history.clone(),
23            })
24            .expect("round update input encoding should succeed"),
25        })]
26    }
27
28    #[allow(deprecated)]
29    pub fn prepare(
30        &self,
31        settings: &PreparationSettings,
32    ) -> Result<PreparedRoundUpdateTransactionV1, PrepareError> {
33        let prepared_instructions =
34            InstructionsV1(self.create_instructions()).prepare_partial(settings)?;
35        let encoded_source = manifest_encode(&self)?;
36        // Minor TODO - for a slight performance improvement, change this to be read from the decoder
37        // As per the other hashes, don't include the prefix byte
38        let source_hash = hash(&encoded_source[1..]);
39        let instructions_hash = prepared_instructions.summary.hash;
40        let round_update_hash = HashAccumulator::new()
41            .concat([
42                TRANSACTION_HASHABLE_PAYLOAD_PREFIX,
43                TransactionDiscriminator::V1RoundUpdate as u8,
44            ])
45            // We include the full source transaction contents
46            .concat(source_hash)
47            // We also include the instructions hash, so the exact instructions can be proven
48            .concat(instructions_hash)
49            .finalize();
50        Ok(PreparedRoundUpdateTransactionV1 {
51            encoded_instructions: manifest_encode(&prepared_instructions.inner.0)?,
52            references: prepared_instructions.references,
53            blobs: index_map_new(),
54            summary: Summary {
55                effective_length: prepared_instructions.summary.effective_length,
56                total_bytes_hashed: prepared_instructions.summary.total_bytes_hashed,
57                hash: round_update_hash,
58            },
59        })
60    }
61}
62
63impl TransactionPayload for RoundUpdateTransactionV1 {
64    type Prepared = PreparedRoundUpdateTransactionV1;
65    type Raw = RawRoundUpdateTransactionV1;
66}
67
68pub struct PreparedRoundUpdateTransactionV1 {
69    pub encoded_instructions: Vec<u8>,
70    pub references: IndexSet<Reference>,
71    pub blobs: IndexMap<Hash, Vec<u8>>,
72    pub summary: Summary,
73}
74
75impl_has_summary!(PreparedRoundUpdateTransactionV1);
76
77define_raw_transaction_payload!(RawRoundUpdateTransactionV1, TransactionPayloadKind::Other);
78
79impl PreparedTransaction for PreparedRoundUpdateTransactionV1 {
80    type Raw = RawRoundUpdateTransactionV1;
81
82    fn prepare_from_transaction_enum(
83        decoder: &mut TransactionDecoder,
84    ) -> Result<Self, PrepareError> {
85        let decoded = RoundUpdateTransactionV1::from_payload_variant(decoder.decode()?);
86        decoded.prepare(decoder.settings())
87    }
88}
89
90impl TransactionPreparableFromValue for PreparedRoundUpdateTransactionV1 {
91    fn prepare_from_value(decoder: &mut TransactionDecoder) -> Result<Self, PrepareError> {
92        let decoded = decoder.decode::<RoundUpdateTransactionV1>()?;
93        decoded.prepare(decoder.settings())
94    }
95}
96
97impl PreparedRoundUpdateTransactionV1 {
98    pub fn create_executable(self) -> ExecutableTransaction {
99        ExecutableTransaction::new_v1(
100            self.encoded_instructions,
101            AuthZoneInit::proofs(btreeset!(system_execution(SystemExecution::Validator))),
102            self.references,
103            self.blobs,
104            ExecutionContext {
105                unique_hash: self.summary.hash,
106                intent_hash_nullifications: vec![],
107                epoch_range: None,
108                payload_size: 0,
109                num_of_signature_validations: 0,
110                costing_parameters: TransactionCostingParameters {
111                    tip: TipSpecifier::None,
112                    free_credit_in_xrd: Decimal::ZERO,
113                },
114                pre_allocated_addresses: vec![],
115                disable_limits_and_costing_modules: true,
116                proposer_timestamp_range: None,
117            },
118        )
119    }
120}
121
122define_wrapped_hash!(RoundUpdateTransactionHash);
123
124impl HasRoundUpdateTransactionHash for PreparedRoundUpdateTransactionV1 {
125    fn round_update_transaction_hash(&self) -> RoundUpdateTransactionHash {
126        RoundUpdateTransactionHash::from_hash(self.summary.hash)
127    }
128}
129
130pub trait HasRoundUpdateTransactionHash {
131    fn round_update_transaction_hash(&self) -> RoundUpdateTransactionHash;
132}