miden_objects/account/account_id/
id_anchor.rs

1use crate::{
2    Digest, EMPTY_WORD,
3    block::{BlockHeader, BlockNumber},
4    errors::AccountIdError,
5};
6
7// ACCOUNT ID ANCHOR
8// ================================================================================================
9
10/// The anchor of an [`AccountId`](crate::account::AccountId). See the type's documentation for
11/// details on anchors.
12///
13/// This type is recommended to be created from a reference to a [`BlockHeader`] via the `TryFrom`
14/// impl.
15///
16/// # Constraints
17///
18/// This type enforces the following constraints.
19/// - The `anchor_block_number` % 2^[`BlockNumber::EPOCH_LENGTH_EXPONENT`] must be zero. In other
20///   words, the block number must a multiple of 2^[`BlockNumber::EPOCH_LENGTH_EXPONENT`].
21/// - The epoch derived from the `anchor_block_number` must be strictly less than [`u16::MAX`].
22#[derive(Debug, Clone, Copy)]
23pub struct AccountIdAnchor {
24    epoch: u16,
25    block_commitment: Digest,
26}
27
28impl AccountIdAnchor {
29    // CONSTANTS
30    // --------------------------------------------------------------------------------------------
31
32    /// A "pre-genesis" [`AccountIdAnchor`] which can be used to anchor accounts created in the
33    /// genesis block.
34    ///
35    /// This anchor should only be used for accounts included in the genesis state, but should not
36    /// be used as actual anchors in a running network. The reason is that this anchor has the same
37    /// `epoch` as the genesis block will have (epoch `0`). However, the genesis block will have a
38    /// different block_commitment than this anchor ([`EMPTY_WORD`]) and so any account ID that
39    /// would use this anchor would be rejected as invalid by the transaction kernel.
40    pub const PRE_GENESIS: Self = Self {
41        epoch: 0,
42        block_commitment: Digest::new(EMPTY_WORD),
43    };
44
45    // CONSTRUCTORS
46    // --------------------------------------------------------------------------------------------
47
48    /// Creates a new [`AccountIdAnchor`] from the provided `anchor_block_number` and
49    /// `anchor_block_commitment`.
50    ///
51    /// # Errors
52    ///
53    /// Returns an error if any of the anchor constraints are not met. See the [type
54    /// documentation](AccountIdAnchor) for details.
55    pub fn new(
56        anchor_block_number: BlockNumber,
57        anchor_block_commitment: Digest,
58    ) -> Result<Self, AccountIdError> {
59        if anchor_block_number.as_u32() & 0x0000_ffff != 0 {
60            return Err(AccountIdError::AnchorBlockMustBeEpochBlock);
61        }
62
63        let anchor_epoch = anchor_block_number.block_epoch();
64
65        if anchor_epoch == u16::MAX {
66            return Err(AccountIdError::AnchorEpochMustNotBeU16Max);
67        }
68
69        Ok(Self {
70            epoch: anchor_epoch,
71            block_commitment: anchor_block_commitment,
72        })
73    }
74
75    /// Creates a new [`AccountIdAnchor`] from the provided `anchor_epoch` and
76    /// `anchor_block_commitment` without validation.
77    ///
78    /// # Warning
79    ///
80    /// The caller must ensure validity of the `anchor_epoch`, in particular the correctness of the
81    /// relationship between the `anchor_epoch` and the provided `anchor_block_commitment`.
82    ///
83    /// # Panics
84    ///
85    /// If debug_assertions are enabled (e.g. in debug mode), this function panics if the
86    /// `anchor_epoch` is [`u16::MAX`].
87    pub fn new_unchecked(anchor_epoch: u16, anchor_block_commitment: Digest) -> Self {
88        debug_assert_ne!(anchor_epoch, u16::MAX, "anchor epoch cannot be u16::MAX");
89
90        Self {
91            epoch: anchor_epoch,
92            block_commitment: anchor_block_commitment,
93        }
94    }
95
96    // PUBLIC ACCESSORS
97    // --------------------------------------------------------------------------------------------
98
99    /// Returns the epoch of this anchor.
100    pub fn epoch(self) -> u16 {
101        self.epoch
102    }
103
104    /// Returns the block commitment of this anchor.
105    pub fn block_commitment(self) -> Digest {
106        self.block_commitment
107    }
108}
109
110// CONVERSIONS TO ACCOUNT ID ANCHOR
111// ================================================================================================
112
113impl TryFrom<&BlockHeader> for AccountIdAnchor {
114    type Error = AccountIdError;
115
116    /// Extracts the [`BlockHeader::block_num`] and [`BlockHeader::commitment`] from the provided
117    /// `block_header` and tries to convert it to an [`AccountIdAnchor`].
118    ///
119    /// # Errors
120    ///
121    /// Returns an error if any of the anchor constraints are not met. See the [type
122    /// documentation](AccountIdAnchor) for details.
123    fn try_from(block_header: &BlockHeader) -> Result<Self, Self::Error> {
124        Self::new(block_header.block_num(), block_header.commitment())
125    }
126}