casper_storage/
address_generator.rs

1//! Generates unique 32-byte addresses.
2use rand::{RngCore, SeedableRng};
3use rand_chacha::ChaChaRng;
4
5use casper_types::{AccessRights, Digest, Phase, URef};
6
7/// The length of an address.
8pub const ADDRESS_LENGTH: usize = 32;
9
10/// Alias for an array of bytes that represents an address.
11pub type Address = [u8; ADDRESS_LENGTH];
12
13const SEED_LENGTH: usize = 32;
14
15/// An `AddressGenerator` generates `URef` addresses.
16pub struct AddressGenerator(ChaChaRng);
17
18impl AddressGenerator {
19    /// Creates an [`AddressGenerator`] from a 32-byte hash digest and [`Phase`].
20    pub fn new(hash: &[u8], phase: Phase) -> AddressGenerator {
21        AddressGeneratorBuilder::new()
22            .seed_with(hash)
23            .seed_with(&[phase as u8])
24            .build()
25    }
26
27    /// Creates a new [`Address`] by using an internal instance of PRNG.
28    pub fn create_address(&mut self) -> Address {
29        let mut buff = [0u8; ADDRESS_LENGTH];
30        self.0.fill_bytes(&mut buff);
31        buff
32    }
33
34    /// Creates a new [`Address`] by hashing an output from [`AddressGenerator::create_address`]
35    /// with a blake2b256.
36    pub fn new_hash_address(&mut self) -> Address {
37        Digest::hash(self.create_address()).value()
38    }
39
40    /// Creates a new [`URef`] with a new address generated.
41    pub fn new_uref(&mut self, access_rights: AccessRights) -> URef {
42        let addr = self.create_address();
43        URef::new(addr, access_rights)
44    }
45}
46
47/// A builder for [`AddressGenerator`].
48#[derive(Default)]
49pub struct AddressGeneratorBuilder {
50    data: Vec<u8>,
51}
52
53impl AddressGeneratorBuilder {
54    /// Creates a new builder.
55    pub fn new() -> Self {
56        Default::default()
57    }
58
59    /// Extends the seed with more data.
60    pub fn seed_with(mut self, bytes: &[u8]) -> Self {
61        self.data.extend(bytes);
62        self
63    }
64
65    /// Creates a new [`AddressGenerator`].
66    ///
67    /// This method hashes the seed bytes, and seeds the PRNG with it.
68    pub fn build(self) -> AddressGenerator {
69        let seed: [u8; SEED_LENGTH] = Digest::hash(self.data).value();
70        AddressGenerator(ChaChaRng::from_seed(seed))
71    }
72}
73
74#[cfg(test)]
75mod tests {
76    use casper_types::Phase;
77
78    use super::AddressGenerator;
79
80    const DEPLOY_HASH_1: [u8; 32] = [1u8; 32];
81    const DEPLOY_HASH_2: [u8; 32] = [2u8; 32];
82
83    #[test]
84    fn should_generate_different_numbers_for_different_seeds() {
85        let mut ag_a = AddressGenerator::new(&DEPLOY_HASH_1, Phase::Session);
86        let mut ag_b = AddressGenerator::new(&DEPLOY_HASH_2, Phase::Session);
87        let random_a = ag_a.create_address();
88        let random_b = ag_b.create_address();
89
90        assert_ne!(random_a, random_b)
91    }
92
93    #[test]
94    fn should_generate_same_numbers_for_same_seed() {
95        let mut ag_a = AddressGenerator::new(&DEPLOY_HASH_1, Phase::Session);
96        let mut ag_b = AddressGenerator::new(&DEPLOY_HASH_1, Phase::Session);
97        let random_a = ag_a.create_address();
98        let random_b = ag_b.create_address();
99
100        assert_eq!(random_a, random_b)
101    }
102
103    #[test]
104    fn should_not_generate_same_numbers_for_different_phase() {
105        let mut ag_a = AddressGenerator::new(&DEPLOY_HASH_1, Phase::Payment);
106        let mut ag_b = AddressGenerator::new(&DEPLOY_HASH_1, Phase::Session);
107        let mut ag_c = AddressGenerator::new(&DEPLOY_HASH_1, Phase::FinalizePayment);
108        let random_a = ag_a.create_address();
109        let random_b = ag_b.create_address();
110        let random_c = ag_c.create_address();
111
112        assert_ne!(
113            random_a, random_b,
114            "different phase should have different output"
115        );
116
117        assert_ne!(
118            random_a, random_c,
119            "different phase should have different output"
120        );
121    }
122}