snarkvm_ledger_debug/
check_next_block.rs

1// Copyright (C) 2019-2023 Aleo Systems Inc.
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7// http://www.apache.org/licenses/LICENSE-2.0
8
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use super::*;
16
17use rand::{rngs::StdRng, SeedableRng};
18
19impl<N: Network, C: ConsensusStorage<N>> Ledger<N, C> {
20    /// Checks the given block is valid next block.
21    pub fn check_next_block<R: CryptoRng + Rng>(&self, block: &Block<N>, rng: &mut R) -> Result<()> {
22        let height = block.height();
23
24        // Ensure the block hash does not already exist.
25        if self.contains_block_hash(&block.hash())? {
26            bail!("Block hash '{}' already exists in the ledger", block.hash())
27        }
28
29        // Ensure the block height does not already exist.
30        if self.contains_block_height(block.height())? {
31            bail!("Block height '{height}' already exists in the ledger")
32        }
33
34        // Ensure the solutions do not already exist.
35        if let Some(solutions) = block.solutions() {
36            for puzzle_commitment in solutions.puzzle_commitments() {
37                if self.contains_puzzle_commitment(puzzle_commitment)? {
38                    bail!("Puzzle commitment {puzzle_commitment} already exists in the ledger");
39                }
40            }
41        }
42
43        // Ensure each transaction is well-formed and unique.
44        // TODO: this intermediate allocation shouldn't be necessary; this is most likely https://github.com/rust-lang/rust/issues/89418.
45        let transactions = block.transactions().iter().collect::<Vec<_>>();
46        let rngs = (0..transactions.len()).map(|_| StdRng::from_seed(rng.gen())).collect::<Vec<_>>();
47        cfg_iter!(transactions).zip(rngs).try_for_each(|(transaction, mut rng)| {
48            self.check_transaction_basic(*transaction, transaction.to_rejected_id()?, &mut rng)
49                .map_err(|e| anyhow!("Invalid transaction found in the transactions list: {e}"))
50        })?;
51
52        // TODO (howardwu): Remove this after moving the total supply into credits.aleo.
53        {
54            // // Retrieve the latest total supply.
55            // let latest_total_supply = self.latest_total_supply_in_microcredits();
56            // // Retrieve the block reward from the first block ratification.
57            // let block_reward = match block.ratifications()[0] {
58            //     Ratify::BlockReward(block_reward) => block_reward,
59            //     _ => bail!("Block {height} is invalid - the first ratification must be a block reward"),
60            // };
61            // // Retrieve the puzzle reward from the second block ratification.
62            // let puzzle_reward = match block.ratifications()[1] {
63            //     Ratify::PuzzleReward(puzzle_reward) => puzzle_reward,
64            //     _ => bail!("Block {height} is invalid - the second ratification must be a puzzle reward"),
65            // };
66            // // Compute the next total supply in microcredits.
67            // let next_total_supply_in_microcredits =
68            //     update_total_supply(latest_total_supply, block_reward, puzzle_reward, block.transactions())?;
69            // // Ensure the total supply in microcredits is correct.
70            // if next_total_supply_in_microcredits != block.total_supply_in_microcredits() {
71            //     bail!("Invalid total supply in microcredits")
72            // }
73        }
74
75        // Construct the finalize state.
76        let state = FinalizeGlobalState::new::<N>(
77            block.round(),
78            block.height(),
79            block.cumulative_weight(),
80            block.cumulative_proof_target(),
81            block.previous_hash(),
82        )?;
83
84        // Ensure speculation over the unconfirmed transactions is correct.
85        let ratified_finalize_operations =
86            self.vm.check_speculate(state, block.ratifications(), block.solutions(), block.transactions())?;
87
88        // Ensure the block is correct.
89        block.verify(
90            &self.latest_block(),
91            self.latest_state_root(),
92            &self.latest_committee()?,
93            self.coinbase_puzzle(),
94            &self.latest_epoch_challenge()?,
95            OffsetDateTime::now_utc().unix_timestamp(),
96            ratified_finalize_operations,
97        )?;
98
99        Ok(())
100    }
101}