ex3-block-builder 0.15.29

EX3 block report data structure.
Documentation
use ex3_canister_types::range::ReportRange;
use ex3_crypto::sha256;
use ex3_deposit_detector_public_types::ConsumedDepositShardingSubReport;
use ex3_node_types::range::CandidRange;
use ex3_node_types::transaction::EncodedTransaction;
use ex3_node_types::BlockHeight;
use ex3_node_types::MerkleNode;

use rs_merkle::algorithms::Sha256;
use rs_merkle::MerkleTree;

use crate::{BlockBuilder, SnapshotVaultIndex};

impl BlockBuilder {
    /// Generate consumed deposit tx sharding sub reports
    pub(crate) fn generate_consumed_deposit_sharding_sub_reports(
        &self,
        consumed_deposit_txs: Vec<(EncodedTransaction, usize)>,
        txs_merkle_tree: &MerkleTree<Sha256>,
    ) -> Vec<ConsumedDepositShardingSubReport> {
        let mut sharding_sub_reports = vec![];
        let mut consumed_deposit_txs = consumed_deposit_txs;
        let total_tx_count = txs_merkle_tree.leaves_len();
        if consumed_deposit_txs.is_empty() {
            return vec![];
        }

        let full_range = CandidRange {
            start: 0u32,
            end: consumed_deposit_txs.len().try_into().unwrap(),
        };

        loop {
            // take
            let mut deposit_txs = vec![];
            for _ in 0..self.max_consumed_deposit_per_sharding_sub_report {
                if consumed_deposit_txs.len() == 0 {
                    break;
                }
                let tx = consumed_deposit_txs.remove(0);
                deposit_txs.push(tx);
            }

            if deposit_txs.is_empty() {
                break;
            }

            let (txs, indexes) = deposit_txs
                .into_iter()
                .map(|(tx, index)| (tx, index.clone()))
                .unzip::<EncodedTransaction, usize, Vec<EncodedTransaction>, Vec<usize>>();

            let merkle_proof = txs_merkle_tree.proof(&indexes);
            let report_start = sharding_sub_reports.len()
                * self
                    .max_core_registry_update_tx_per_sharding_sub_report
                    .clone();

            let report_end = report_start.clone() + txs.len();
            let report_range = CandidRange {
                start: report_start.try_into().unwrap(),
                end: report_end.try_into().unwrap(),
            };

            let report = ConsumedDepositShardingSubReport {
                merkle_proof: merkle_proof.to_bytes(),
                range: ReportRange {
                    total_count: total_tx_count.clone().try_into().unwrap(),
                    sharding_range: full_range.clone(),
                    report_range,
                },
                deposit_txs: txs,
                deposit_tx_indexes: indexes.into_iter().map(|i| i.try_into().unwrap()).collect(),
            };
            sharding_sub_reports.push(report);
        }

        sharding_sub_reports
    }

    /// Generate deposit detector data integrity
    pub(crate) fn generate_deposit_detector_data_integrity(
        &self,
        current_block_height: &BlockHeight,
        consumed_deposits_sharding_sub_reports: &Vec<ConsumedDepositShardingSubReport>,
        snapshot_vault_index: &SnapshotVaultIndex,
    ) -> MerkleNode {
        let total_merkle_node_count = snapshot_vault_index.get_total_merkle_node_count();

        let mut data_buffer = vec![];

        // 2.1. current_block_height_bytes: the block height of the current processed block
        data_buffer.extend(current_block_height.0.to_bytes_le());

        // 2.2. canister_id_bytes: deposit detector canister id
        let canister_id = self.deposit_detector_canister_id;
        data_buffer.extend(canister_id.as_slice());

        // 2.3. total_consumed_deposit_count_bytes: the total count of core registry update txs
        let total_consumed_deposit_count: u32 = consumed_deposits_sharding_sub_reports
            .iter()
            .fold(0usize, |acc, report| acc + report.deposit_txs.len())
            .try_into()
            .unwrap();

        data_buffer.extend(total_consumed_deposit_count.to_le_bytes());

        // 2.4. total_merkle_node_count_bytes
        data_buffer.extend(total_merkle_node_count.to_le_bytes());

        // 2.5. canister_index_bytes: the index of the core registry canister
        //   in the data integrity merkle tree
        data_buffer.extend(
            snapshot_vault_index
                .get_deposit_detector_index()
                .to_le_bytes(),
        );

        // 2.6. data_bytes: the bytes of current sharding report txs
        consumed_deposits_sharding_sub_reports
            .iter()
            .for_each(|report| {
                data_buffer.extend(report.merkle_proof.as_slice());
            });

        let core_registry_data_integrity: MerkleNode = sha256(data_buffer);
        core_registry_data_integrity
    }
}