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
// Copyright (C) 2019-2022 Aleo Systems Inc.
// This file is part of the snarkVM library.

// The snarkVM library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// The snarkVM library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with the snarkVM library. If not, see <https://www.gnu.org/licenses/>.

use super::*;
use crate::ProgramStorage;

impl<N: Network> Block<N> {
    /// Initializes a new genesis block.
    pub fn genesis<P: ProgramStorage<N>, R: Rng + CryptoRng>(
        vm: &VM<N, P>,
        private_key: &PrivateKey<N>,
        rng: &mut R,
    ) -> Result<Self> {
        // Prepare the caller.
        let caller = Address::try_from(private_key)?;
        // Prepare the program ID.
        let program_id = FromStr::from_str("credits.aleo")?;
        // Prepare the function name.
        let function_name = FromStr::from_str("genesis")?;
        // Prepare the function inputs.
        let inputs = [Value::from_str(&caller.to_string())?, Value::from_str("1_100_000_000_000_000_u64")?];
        // Authorize the call to start.
        let authorization = vm.authorize(private_key, &program_id, function_name, &inputs, rng)?;
        // Execute the genesis function.
        let transaction = Transaction::execute_authorization(vm, authorization, rng)?;

        // Prepare the transactions.
        let transactions = Transactions::from(&[transaction]);
        // Prepare the block header.
        let header = Header::genesis(&transactions)?;
        // Prepare the previous block hash.
        let previous_hash = N::BlockHash::default();

        // Construct the block.
        let block = Self::new(private_key, previous_hash, header, transactions, rng)?;
        // Ensure the block is valid genesis block.
        match block.is_genesis() {
            true => Ok(block),
            false => bail!("Failed to initialize a genesis block"),
        }
    }

    /// Returns `true` if the block is a genesis block.
    pub fn is_genesis(&self) -> bool {
        // Ensure the previous block hash is zero.
        self.previous_hash == N::BlockHash::default()
            // Ensure the header is a genesis block header.
            && self.header.is_genesis()
            // Ensure there is 1 transaction in the genesis block.
            && self.transactions.len() == 1
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_genesis() {
        let block = crate::ledger::test_helpers::sample_genesis_block();
        // println!("{}", serde_json::to_string_pretty(&block).unwrap());
        assert!(block.is_genesis());
    }
}