miden_objects/account/account_id/
id_anchor.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use crate::{
    block::{BlockHeader, BlockNumber},
    errors::AccountIdError,
    Digest, EMPTY_WORD,
};

// ACCOUNT ID ANCHOR
// ================================================================================================

/// The anchor of an [`AccountId`](crate::account::AccountId). See the type's documentation for
/// details on anchors.
///
/// This type is recommended to be created from a reference to a [`BlockHeader`] via the `TryFrom`
/// impl.
///
/// # Constraints
///
/// This type enforces the following constraints.
/// - The `anchor_block_number` % 2^[`BlockNumber::EPOCH_LENGTH_EXPONENT`] must be zero. In other
///   words, the block number must a multiple of 2^[`BlockNumber::EPOCH_LENGTH_EXPONENT`].
/// - The epoch derived from the `anchor_block_number` must be strictly less than [`u16::MAX`].
#[derive(Debug, Clone, Copy)]
pub struct AccountIdAnchor {
    epoch: u16,
    block_hash: Digest,
}

impl AccountIdAnchor {
    // CONSTANTS
    // --------------------------------------------------------------------------------------------

    /// A "pre-genesis" [`AccountIdAnchor`] which can be used to anchor accounts created in the
    /// genesis block.
    ///
    /// This anchor should only be used for accounts included in the genesis state, but should not
    /// be used as actual anchors in a running network. The reason is that this anchor has the same
    /// `epoch` as the genesis block will have (epoch `0`). However, the genesis block will have a
    /// different block_hash than this anchor ([`EMPTY_WORD`]) and so any account ID that would use
    /// this anchor would be rejected as invalid by the transaction kernel.
    pub const PRE_GENESIS: Self = Self {
        epoch: 0,
        block_hash: Digest::new(EMPTY_WORD),
    };

    // CONSTRUCTORS
    // --------------------------------------------------------------------------------------------

    /// Creates a new [`AccountIdAnchor`] from the provided `anchor_block_number` and
    /// `anchor_block_hash`.
    ///
    /// # Errors
    ///
    /// Returns an error if any of the anchor constraints are not met. See the [type
    /// documentation](AccountIdAnchor) for details.
    pub fn new(
        anchor_block_number: BlockNumber,
        anchor_block_hash: Digest,
    ) -> Result<Self, AccountIdError> {
        if anchor_block_number.as_u32() & 0x0000_ffff != 0 {
            return Err(AccountIdError::AnchorBlockMustBeEpochBlock);
        }

        let anchor_epoch = anchor_block_number.block_epoch();

        if anchor_epoch == u16::MAX {
            return Err(AccountIdError::AnchorEpochMustNotBeU16Max);
        }

        Ok(Self {
            epoch: anchor_epoch,
            block_hash: anchor_block_hash,
        })
    }

    /// Creates a new [`AccountIdAnchor`] from the provided `anchor_epoch` and `anchor_block_hash`
    /// without validation.
    ///
    /// # Warning
    ///
    /// The caller must ensure validity of the `anchor_epoch`, in particular the correctness of the
    /// relationship between the `anchor_epoch` and the provided `anchor_block_hash`.
    ///
    /// # Panics
    ///
    /// If debug_assertions are enabled (e.g. in debug mode), this function panics if the
    /// `anchor_epoch` is [`u16::MAX`].
    pub fn new_unchecked(anchor_epoch: u16, anchor_block_hash: Digest) -> Self {
        debug_assert_ne!(anchor_epoch, u16::MAX, "anchor epoch cannot be u16::MAX");

        Self {
            epoch: anchor_epoch,
            block_hash: anchor_block_hash,
        }
    }

    // PUBLIC ACCESSORS
    // --------------------------------------------------------------------------------------------

    /// Returns the epoch of this anchor.
    pub fn epoch(self) -> u16 {
        self.epoch
    }

    /// Returns the block hash of this anchor.
    pub fn block_hash(self) -> Digest {
        self.block_hash
    }
}

// CONVERSIONS TO ACCOUNT ID ANCHOR
// ================================================================================================

impl TryFrom<&BlockHeader> for AccountIdAnchor {
    type Error = AccountIdError;

    /// Extracts the [`BlockHeader::block_num`] and [`BlockHeader::hash`] from the provided
    /// `block_header` and tries to convert it to an [`AccountIdAnchor`].
    ///
    /// # Errors
    ///
    /// Returns an error if any of the anchor constraints are not met. See the [type
    /// documentation](AccountIdAnchor) for details.
    fn try_from(block_header: &BlockHeader) -> Result<Self, Self::Error> {
        Self::new(block_header.block_num(), block_header.hash())
    }
}