radix_engine/kernel/
id_allocator.rs

1use crate::errors::{IdAllocationError, KernelError, RuntimeError};
2use crate::internal_prelude::*;
3
4/// An ID allocator defines how identities are generated.
5#[derive(Debug, Clone, PartialEq, Eq)]
6pub struct IdAllocator {
7    transaction_hash: Hash,
8    next_id: u32,
9}
10
11impl IdAllocator {
12    pub fn new(transaction_hash: Hash) -> Self {
13        Self {
14            transaction_hash,
15            next_id: 0u32,
16        }
17    }
18
19    pub fn allocate_node_id(&mut self, entity_type: EntityType) -> Result<NodeId, RuntimeError> {
20        let node_id = self
21            .next_node_id(entity_type)
22            .map_err(|e| RuntimeError::KernelError(KernelError::IdAllocationError(e)))?;
23
24        Ok(node_id)
25    }
26
27    fn next(&mut self) -> Result<u32, IdAllocationError> {
28        if self.next_id == u32::MAX {
29            Err(IdAllocationError::OutOfID)
30        } else {
31            let rtn = self.next_id;
32            self.next_id += 1;
33            Ok(rtn)
34        }
35    }
36
37    fn next_node_id(&mut self, entity_type: EntityType) -> Result<NodeId, IdAllocationError> {
38        // Compute `hash(transaction_hash, index)`
39        let mut buf = [0u8; Hash::LENGTH + 4];
40        buf[..Hash::LENGTH].copy_from_slice(self.transaction_hash.as_ref());
41        buf[Hash::LENGTH..].copy_from_slice(&self.next()?.to_le_bytes());
42        let hash = hash(buf);
43
44        // Install the entity type
45        let mut node_id: [u8; NodeId::LENGTH] = hash.lower_bytes();
46        node_id[0] = entity_type as u8;
47
48        Ok(NodeId(node_id))
49    }
50}