fn import_block(
        &mut self,
        header: BlockHeader,
        clock: &impl Clock,
    ) -> Result<ImportResult, Error> {
        let hash = header.block_hash();
        let tip = self.chain.last();
        let best = tip.hash;

        // Block extends the active chain.
        if header.prev_blockhash == best {
            let height = tip.height + 1;

            self.validate(&tip, &header, clock)?;
            self.extend_chain(height, hash, header);
            self.store.put(std::iter::once(header))?;
        } else if self.headers.contains_key(&hash) || self.orphans.contains_key(&hash) {
            // FIXME: This shouldn't be an error.
            return Err(Error::DuplicateBlock(hash));
        } else {
            if let Some(height) = self.headers.get(&header.prev_blockhash) {
                // Don't accept any forks from the main chain, prior to the last checkpoint.
                if *height < self.last_checkpoint() {
                    return Err(Error::InvalidBlockHeight(*height + 1));
                }
            }

            // Validate that the block's PoW (1) is valid against its difficulty target, and (2)
            // is greater than the minimum allowed for this network.
            //
            // We do this because it's cheap to verify and prevents flooding attacks.
            let target = header.target();
            match header.validate_pow(&target) {
                Ok(_) => {
                    let limit = self.params.pow_limit;
                    if target > limit {
                        return Err(Error::InvalidBlockTarget(target, limit));
                    }
                }
                Err(bitcoin::util::Error::BlockBadProofOfWork) => {
                    return Err(Error::InvalidBlockPoW);
                }
                Err(bitcoin::util::Error::BlockBadTarget) => {
                    // The only way to get a 'bad target' error is to pass a different target
                    // than the one specified in the header.
                    unreachable!();
                }
                Err(_) => {
                    // We've handled all possible errors above.
                    unreachable!();
                }
            }
            self.orphans.insert(hash, header);
        }

        // Activate the chain with the most work.

        let candidates = self.chain_candidates(clock);

        // TODO: What are we trying to do here? We're saying that if there are no
        // forks, and this header has no parent, we return an error. But:
        //
        // If there are forks, it doesn't mean this header is part of one. It could
        // be a fork that already existed before this header was received.
        //
        // What we should do is simply: if the block has no parent (is orphan), we
        // know it's a no-op, ie. we won't discover a better branch. So we always
        // return the error without even checking for candidates. Otherwise, if
        // it *does* have a parent, we check for candidates.
        if candidates.is_empty()
            && !self.headers.contains_key(&header.prev_blockhash)
            && !self.orphans.contains_key(&header.prev_blockhash)
        {
            // FIXME: This shouldn't be an error.
            return Err(Error::BlockMissing(header.prev_blockhash));
        }

        // Stale blocks after potential re-org.
        let mut stale = Vec::new();

        // TODO: Don't switch multiple times. Switch to the best branch in one go.
        for branch in candidates.iter() {
            let candidate_work = Branch(&branch.headers).work();
            let main_work = Branch(self.chain_suffix(branch.fork_height)).work();

            // TODO: Validate branch before switching to it.
            if candidate_work > main_work {
                stale = self.switch_to_fork(branch)?;
            } else if self.params.network != Network::Bitcoin {
                if candidate_work == main_work {
                    // Nb. We intend here to compare the hashes as integers, and pick the lowest
                    // hash as the winner. However, the `PartialEq` on `BlockHash` is implemented on
                    // the underlying `[u8]` array, and does something different (lexographical
                    // comparison). Since this code isn't run on Mainnet, it's okay, as it serves
                    // its purpose of being determinstic when choosing the active chain.
                    if branch.tip < self.chain.last().hash {
                        stale = self.switch_to_fork(branch)?;
                    }
                }
            }
        }

        let (hash, _) = self.tip();
        if hash != best {
            // TODO: Test the reverted blocks.
            Ok(ImportResult::TipChanged(
                hash,
                self.height(),
                stale.into_iter().map(|h| h.block_hash()).collect(),
            ))
        } else {
            Ok(ImportResult::TipUnchanged)
        }
    }
/// Import a block into the tree. Performs header validation. This function may trigger
/// a chain re-org.
Import a block into the tree. Performs header validation. This function may trigger
a chain re-org.
Import a block into the tree . Performs header validation . This function may trigger a chain re - org .
fn import_block(
        &mut self,
        header: BlockHeader,
        clock: &impl Clock,
    ) -> Result<ImportResult, Error> {
        let hash = header.block_hash();
        let tip = self.chain.last();
        let best = tip.hash;
        // Block extends the active chain.
        if header.prev_blockhash == best {
            let height = tip.height + 1;
            self.validate(&tip, &header, clock)?;
            self.extend_chain(height, hash, header);
            self.store.put(std::iter::once(header))?;
        } else if self.headers.contains_key(&hash) || self.orphans.contains_key(&hash) {
            // FIXME: This shouldn't be an error.
            return Err(Error::DuplicateBlock(hash));
        } else {
            if let Some(height) = self.headers.get(&header.prev_blockhash) {
                // Don't accept any forks from the main chain, prior to the last checkpoint.
                if *height < self.last_checkpoint() {
                    return Err(Error::InvalidBlockHeight(*height + 1));
                }
            }
            // Validate that the block's PoW (1) is valid against its difficulty target, and (2)
            // is greater than the minimum allowed for this network.
            //
            // We do this because it's cheap to verify and prevents flooding attacks.
            let target = header.target();
            match header.validate_pow(&target) {
                Ok(_) => {
                    let limit = self.params.pow_limit;
                    if target > limit {
                        return Err(Error::InvalidBlockTarget(target, limit));
                    }
                }
                Err(bitcoin::util::Error::BlockBadProofOfWork) => {
                    return Err(Error::InvalidBlockPoW);
                }
                Err(bitcoin::util::Error::BlockBadTarget) => {
                    // The only way to get a 'bad target' error is to pass a different target
                    // than the one specified in the header.
                    unreachable!();
                }
                Err(_) => {
                    // We've handled all possible errors above.
                    unreachable!();
                }
            }
            self.orphans.insert(hash, header);
        }
        // Activate the chain with the most work.
        let candidates = self.chain_candidates(clock);
        // TODO: What are we trying to do here? We're saying that if there are no
        // forks, and this header has no parent, we return an error. But:
        //
        // If there are forks, it doesn't mean this header is part of one. It could
        // be a fork that already existed before this header was received.
        //
        // What we should do is simply: if the block has no parent (is orphan), we
        // know it's a no-op, ie. we won't discover a better branch. So we always
        // return the error without even checking for candidates. Otherwise, if
        // it *does* have a parent, we check for candidates.
        if candidates.is_empty()
            && !self.headers.contains_key(&header.prev_blockhash)
            && !self.orphans.contains_key(&header.prev_blockhash)
        {
            // FIXME: This shouldn't be an error.
            return Err(Error::BlockMissing(header.prev_blockhash));
        }
        // Stale blocks after potential re-org.
        let mut stale = Vec::new();
        // TODO: Don't switch multiple times. Switch to the best branch in one go.
        for branch in candidates.iter() {
            let candidate_work = Branch(&branch.headers).work();
            let main_work = Branch(self.chain_suffix(branch.fork_height)).work();
            // TODO: Validate branch before switching to it.
            if candidate_work > main_work {
                stale = self.switch_to_fork(branch)?;
            } else if self.params.network != Network::Bitcoin {
                if candidate_work == main_work {
                    // Nb. We intend here to compare the hashes as integers, and pick the lowest
                    // hash as the winner. However, the `PartialEq` on `BlockHash` is implemented on
                    // the underlying `[u8]` array, and does something different (lexographical
                    // comparison). Since this code isn't run on Mainnet, it's okay, as it serves
                    // its purpose of being determinstic when choosing the active chain.
                    if branch.tip < self.chain.last().hash {
                        stale = self.switch_to_fork(branch)?;
                    }
                }
            }
        }
        let (hash, _) = self.tip();
        if hash != best {
            // TODO: Test the reverted blocks.
            Ok(ImportResult::TipChanged(
                hash,
                self.height(),
                stale.into_iter().map(|h| h.block_hash()).collect(),
            ))
        } else {
            Ok(ImportResult::TipUnchanged)
        }
    }
fn import_block ( & mut self , header : BlockHeader , clock : & impl Clock , ) -> Result < ImportResult , Error > { let hash = header . block_hash ( ) ; let tip = self . chain . last ( ) ; let best = tip . hash ; // Block extends the active chain. if header . prev_blockhash == best { let height = tip . height + 1 ; self . validate ( & tip , & header , clock ) ? ; self . extend_chain ( height , hash , header ) ; self . store . put ( std :: iter :: once ( header ) ) ? ; } else if self . headers . contains_key ( & hash ) || self . orphans . contains_key ( & hash ) { // FIXME: This shouldn't be an error. return Err ( Error :: DuplicateBlock ( hash ) ) ; } else { if let Some ( height ) = self . headers . get ( & header . prev_blockhash ) { // Don't accept any forks from the main chain, prior to the last checkpoint. if * height < self . last_checkpoint ( ) { return Err ( Error :: InvalidBlockHeight ( * height + 1 ) ) ; } } // Validate that the block's PoW (1) is valid against its difficulty target, and (2) // is greater than the minimum allowed for this network. // // We do this because it's cheap to verify and prevents flooding attacks. let target = header . target ( ) ; match header . validate_pow ( & target ) { Ok ( _ ) => { let limit = self . params . pow_limit ; if target > limit { return Err ( Error :: InvalidBlockTarget ( target , limit ) ) ; } } Err ( bitcoin :: util :: Error :: BlockBadProofOfWork ) => { return Err ( Error :: InvalidBlockPoW ) ; } Err ( bitcoin :: util :: Error :: BlockBadTarget ) => { // The only way to get a 'bad target' error is to pass a different target // than the one specified in the header. unreachable ! ( ) ; } Err ( _ ) => { // We've handled all possible errors above. unreachable ! ( ) ; } } self . orphans . insert ( hash , header ) ; } // Activate the chain with the most work. let candidates = self . chain_candidates ( clock ) ; // TODO: What are we trying to do here? We're saying that if there are no // forks, and this header has no parent, we return an error. But: // // If there are forks, it doesn't mean this header is part of one. It could // be a fork that already existed before this header was received. // // What we should do is simply: if the block has no parent (is orphan), we // know it's a no-op, ie. we won't discover a better branch. So we always // return the error without even checking for candidates. Otherwise, if // it *does* have a parent, we check for candidates. if candidates . is_empty ( ) && ! self . headers . contains_key ( & header . prev_blockhash ) && ! self . orphans . contains_key ( & header . prev_blockhash ) { // FIXME: This shouldn't be an error. return Err ( Error :: BlockMissing ( header . prev_blockhash ) ) ; } // Stale blocks after potential re-org. let mut stale = Vec :: new ( ) ; // TODO: Don't switch multiple times. Switch to the best branch in one go. for branch in candidates . iter ( ) { let candidate_work = Branch ( & branch . headers ) . work ( ) ; let main_work = Branch ( self . chain_suffix ( branch . fork_height ) ) . work ( ) ; // TODO: Validate branch before switching to it. if candidate_work > main_work { stale = self . switch_to_fork ( branch ) ? ; } else if self . params . network != Network :: Bitcoin { if candidate_work == main_work { // Nb. We intend here to compare the hashes as integers, and pick the lowest // hash as the winner. However, the `PartialEq` on `BlockHash` is implemented on // the underlying `[u8]` array, and does something different (lexographical // comparison). Since this code isn't run on Mainnet, it's okay, as it serves // its purpose of being determinstic when choosing the active chain. if branch . tip < self . chain . last ( ) . hash { stale = self . switch_to_fork ( branch ) ? ; } } } } let ( hash , _ ) = self . tip ( ) ; if hash != best { // TODO: Test the reverted blocks. Ok ( ImportResult :: TipChanged ( hash , self . height ( ) , stale . into_iter ( ) . map ( | h | h . block_hash ( ) ) . collect ( ) , ) ) } else { Ok ( ImportResult :: TipUnchanged ) } }
Import a block into the tree.
Import a block into the tree .
&mut self
header
BlockHeader
clock
&impl Clock