ex3-block-builder 0.15.29

EX3 block report data structure.
Documentation
use ex3_canister_types::range::ReportRange;
use ex3_core_registry_public_types::CoreRegistryUpdateTxShardingSubReport;
use ex3_crypto::sha256;
use ex3_node_types::range::CandidRange;
use ex3_node_types::transaction::EncodedTransaction;
use ex3_node_types::BlockHeight;
use ex3_node_types::MerkleNode;
use std::collections::VecDeque;

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

use crate::{BlockBuilder, SnapshotVaultIndex};

impl BlockBuilder {
    /// Generate core registry update tx sharding sub reports
    pub(crate) fn generate_core_registry_update_tx_sharding_sub_reports(
        &self,
        txs: Vec<(EncodedTransaction, usize)>,
        txs_merkle_tree: &MerkleTree<Sha256>,
    ) -> Vec<CoreRegistryUpdateTxShardingSubReport> {
        let mut core_registry_tx_sharding_sub_reports = vec![];

        let mut txs_mut: VecDeque<_> = txs.into();
        let total_tx_count = txs_merkle_tree.leaves_len();
        if txs_mut.is_empty() {
            return vec![];
        }

        let full_range = CandidRange {
            start: 0u32,
            end: txs_mut.len().try_into().unwrap(),
        };
        loop {
            // take
            let mut txs = vec![];
            for _ in 0..self.max_core_registry_update_tx_per_sharding_sub_report {
                if let Some(tx) = txs_mut.pop_front() {
                    txs.push(tx);
                } else {
                    break;
                }
            }

            if txs.is_empty() {
                break;
            }

            let (txs, indexes) =
                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 = core_registry_tx_sharding_sub_reports.len()
                * self
                    .max_core_registry_update_tx_per_sharding_sub_report
                    .clone() as usize;
            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 = CoreRegistryUpdateTxShardingSubReport {
                merkle_proof: merkle_proof.to_bytes(),
                range: ReportRange {
                    total_count: total_tx_count.clone().try_into().unwrap(),
                    sharding_range: full_range.clone(),
                    report_range,
                },
                txs,
                update_tx_indexes: indexes.into_iter().map(|i| i.try_into().unwrap()).collect(),
            };
            core_registry_tx_sharding_sub_reports.push(report);
        }

        core_registry_tx_sharding_sub_reports
    }

    /// Generate core registry data integrity sharding sub report
    pub(crate) fn generate_core_registry_data_integrity(
        &self,
        current_block_height: &BlockHeight,
        core_register_tx_sharding_sub_reports: &Vec<CoreRegistryUpdateTxShardingSubReport>,
        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: current core registry canister id
        let canister_id = self.core_registry_canister_id;
        data_buffer.extend(canister_id.as_slice());

        // 2.3. total_update_tx_count_bytes: the total count of core registry update txs
        let total_update_tx_count: u32 = core_register_tx_sharding_sub_reports
            .iter()
            .fold(0, |acc, report| acc + report.txs.len())
            .try_into()
            .unwrap();
        data_buffer.extend(total_update_tx_count.to_le_bytes());

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

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

        // 2.5. data_bytes: the bytes of current sharding report txs
        core_register_tx_sharding_sub_reports
            .iter()
            .for_each(|report| data_buffer.extend(&report.merkle_proof));

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