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())
}
}