ckb-light-client-protocol-server 1.2.0

Server-side implementation for CKB light client protocol
Documentation
use ckb_shared::Snapshot;
use ckb_store::ChainStore;
use ckb_types::{
    U256,
    core::{BlockExt, BlockNumber, BlockView, HeaderView},
    packed,
    prelude::*,
    utilities::compact_to_difficulty,
};

#[allow(dead_code)]
pub(crate) trait SnapshotExt {
    fn get_header_by_number(&self, num: BlockNumber) -> Option<HeaderView>;

    fn get_block_by_number(&self, num: BlockNumber) -> Option<BlockView>;

    fn get_block_ext_by_number(&self, num: BlockNumber) -> Option<BlockExt>;

    fn get_verifiable_header_by_number(&self, num: BlockNumber)
    -> Option<packed::VerifiableHeader>;

    fn get_block_difficulty_by_number(&self, num: BlockNumber) -> Option<U256> {
        self.get_header_by_number(num)
            .map(|header| compact_to_difficulty(header.compact_target()))
    }

    fn get_total_difficulty_by_number(&self, num: BlockNumber) -> Option<U256> {
        self.get_block_ext_by_number(num)
            .map(|block_ext| block_ext.total_difficulty)
    }

    fn build_last_state_by_number(&self, num: BlockNumber) -> Option<packed::LightClientMessage> {
        self.get_verifiable_header_by_number(num).map(|header| {
            let content = packed::SendLastState::new_builder()
                .last_header(header)
                .build();
            packed::LightClientMessage::new_builder()
                .set(content)
                .build()
        })
    }
}

impl SnapshotExt for Snapshot {
    fn get_header_by_number(&self, num: BlockNumber) -> Option<HeaderView> {
        self.get_block_hash(num)
            .and_then(|hash| self.get_block_header(&hash))
    }

    fn get_block_by_number(&self, num: BlockNumber) -> Option<BlockView> {
        self.get_block_hash(num)
            .and_then(|hash| self.get_block(&hash))
    }

    fn get_block_ext_by_number(&self, num: BlockNumber) -> Option<BlockExt> {
        self.get_block_hash(num)
            .and_then(|hash| self.get_block_ext(&hash))
    }

    fn get_verifiable_header_by_number(
        &self,
        num: BlockNumber,
    ) -> Option<packed::VerifiableHeader> {
        self.get_block_by_number(num).map(|block| {
            let mmr = self.chain_root_mmr(num - 1);
            let parent_chain_root = mmr.get_root().expect("has chain root");
            packed::VerifiableHeader::new_builder()
                .header(block.data().header())
                .uncles_hash(block.calc_uncles_hash())
                .extension(Pack::pack(&block.extension()))
                .parent_chain_root(parent_chain_root)
                .build()
        })
    }
}