Example #1
0
probe_manager::probe_manager(stack_impl & owner)
    : stack_impl_(owner)
    , timer_(owner.io_service())
    , timer_post_(owner.io_service())
    , timer_probe_(owner.io_service())
{
    // ...
}
Example #2
0
work_manager::work_manager(stack_impl & owner)
    : stack_impl_(owner)
    , strand_(owner.io_service())
    , timer_(owner.io_service())
    , timer_check_work_hosts_(owner.io_service())
    , work_host_index_(0)
{
    // ...
}
Example #3
0
serial_port::serial_port(stack_impl & owner)
    : m_serial_port(owner.io_service())
    , m_device_model(serial::device_model_none)
    , m_hashes_per_second(0.0)
    , stack_impl_(owner)
    , strand_(owner.io_service())
    , timer_(owner.io_service())
{
    // ...
}
Example #4
0
bool db_tx::load_block_index(stack_impl & impl)
{
    if (load_block_index_guts())
    {
        /**
         * Calculate chain trust.
         */
        std::vector<
            std::pair<std::uint32_t, std::shared_ptr<block_index> >
        > sorted_by_height;
        
        sorted_by_height.reserve(globals::instance().block_indexes().size());
        
        const auto & block_indexes = globals::instance().block_indexes();
        
        for (auto & i : block_indexes)
        {
            sorted_by_height.push_back(
                std::make_pair(i.second->height(), i.second)
            );
        }
        
        std::sort(sorted_by_height.begin(), sorted_by_height.end());
        
        for (auto & i : sorted_by_height)
        {
            try
            {
                i.second->m_chain_trust =
                    (i.second->block_index_previous() ?
                    i.second->block_index_previous()->m_chain_trust : 0) +
                    i.second->get_block_trust()
                ;
            }
            catch (std::exception & e)
            {
                log_error("DB TX, what = " << e.what() << ".");
                
                continue;
            }

            /**
             * Calculate the stake modifier checksum.
             */
            i.second->set_stake_modifier_checksum(
                kernel::get_stake_modifier_checksum(i.second)
            );

            if (i.second->height() > 0)
            {
                if (
                    kernel::check_stake_modifier_checkpoints(
                    i.second->m_height, i.second->m_stake_modifier_checksum
                    ) == false)
                {
                    throw std::runtime_error(
                        "failed stake modifier checkpoint"
                    );
                    
                    return false;
                }
            }
        }
        
        /**
         * Set m_DbTxn.
         */
        m_DbTxn = stack_impl::get_db_env()->txn_begin();

        /**
         * Load the best hash chain to the end of the best chain.
         */
        if (read_best_hash_chain(globals::instance().hash_best_chain()) == false)
        {
            if (stack_impl::get_block_index_genesis() == 0)
            {
                return true;
            }
            else
            {
                throw std::runtime_error("best hash chain not loaded");
            
                return false;
            }
        }
        
        if (
            globals::instance().block_indexes().count(
            globals::instance().hash_best_chain()) == 0
            )
        {
            throw std::runtime_error(
                "best hash chain not found in the block index"
            );
            
            return false;
        }

        stack_impl::get_block_index_best() =
            globals::instance().block_indexes()[
            globals::instance().hash_best_chain()]
        ;
        globals::instance().set_best_block_height(
            stack_impl::get_block_index_best()->height()
        );
        stack_impl::get_best_chain_trust() =
            stack_impl::get_block_index_best()->chain_trust()
        ;
        
        log_debug(
            "DB TX hash best chain = " <<
            globals::instance().hash_best_chain().to_string() << ", height = " <<
            stack_impl::get_block_index_best()->m_height << ", trust = " <<
            stack_impl::get_block_index_best()->m_chain_trust.to_string() <<
            ", time = " << stack_impl::get_block_index_best()->m_time << "."
        );
        
        /**
         * Read the sync checkpoint into the checkpoints::hash_sync_checkpoint.
         */
        if (
            read_sync_checkpoint(
            checkpoints::instance().get_hash_sync_checkpoint()) == false
            )
        {
            throw std::runtime_error("read_sync_checkpoint not loaded");
        
            return false;
        }
        
        log_info(
            "DB TX synchronized checkpoint " <<
            checkpoints::instance().get_hash_sync_checkpoint().to_string() <<
            "."
        );
        
        /**
         * Read the best invalid trust if it is found, okay if not found.
         */
        if (read_best_invalid_trust(stack_impl::get_best_invalid_trust()))
        {
            log_info(
                "DB TX read best invalid trust " <<
                stack_impl::get_best_invalid_trust().to_string() << "."
            );
        }
        
        /**
         * Verify the blocks in the best chain.
         * -checklevel (1-6)
         */
        enum { check_level = 1 };
        
        /**
         * Check 1.5 days woth of blocks for clients and 3 days worth of blocks
         * for peers.
         */
#if (defined __ANDROID__ || defined __IPHONE_OS_VERSION_MIN_REQUIRED)
        auto check_depth = 750;
#else
        auto check_depth = 1500;
#endif
        if (check_depth == 0)
        {
            check_depth = 1000000000;
        }
        
        if (check_depth > globals::instance().best_block_height())
        {
            check_depth = globals::instance().best_block_height();
        }
        
        log_debug(
            "DB TX is verifying " << check_depth <<
            " blocks at level << " << check_level << "."
        );

        std::shared_ptr<block_index> index_fork = 0;
        
        std::map<
            std::pair<std::uint32_t, std::uint32_t>,
            std::shared_ptr<block_index>
        > block_positions;
        
        auto checked_blocks = 0;
        
        for (
            auto i = stack_impl::get_block_index_best();
            i && i->block_index_previous();
            i = i->block_index_previous()
            )
        {
            if (
                i->height() < globals::instance().best_block_height() -
                check_depth
                )
            {
                break;
            }
            
            /**
             * Allocate the block.
             */
            block blk;
            
            /**
             * Read the block from disk.
             */
            if (blk.read_from_disk(i))
            {
                float percentage =
                    ((float)checked_blocks / (float)check_depth) * 100.0f
                ;
                
                /**
                 * Only callback status every 100 blocks or 100%.
                 */
                if ((i->height() % 100) == 0 || percentage == 100.0f)
                {
                    /**
                     * Allocate the status.
                     */
                    std::map<std::string, std::string> status;

                    /**
                     * Set the status type.
                     */
                    status["type"] = "database";

                    /**
                     * Format the block verification progress percentage.
                     */
                    std::stringstream ss;

                    ss <<
                        std::fixed << std::setprecision(2) << percentage
                    ;
        
                    /**
                     * Set the status value.
                     */
                    status["value"] = "Verifying " + ss.str() + "%";

                    /**
                     * The block download percentage.
                     */
                    status["blockchain.verify.percent"] =
                        std::to_string(percentage)
                    ;
        
                    /**
                     * Callback
                     */
                    impl.get_status_manager()->insert(status);
                }
                
                try
                {
                    /**
                     * Verify block validity.
                     */
                    if (check_level > 0 && blk.check_block() == false)
                    {
                        log_error(
                            "DB TX Found bad block at " << i->m_height <<
                            ", hash = " << i->get_block_hash().to_string() << "."
                        );
                        
                        index_fork = i->block_index_previous();
                    }
                }
                catch (...)
                {
                    log_error(
                        "DB TX Found bad block at " << i->m_height <<
                        ", hash = " << i->get_block_hash().to_string() << "."
                    );
                    
                    index_fork = i->block_index_previous();
                }

                /**
                 * Increment the number of blocks we have checked in order to
                 * calculate the progress percentage.
                 */
                checked_blocks++;
                
                /**
                 * Verify transaction index validity.
                 */
                if (check_level > 1)
                {
                    auto position = std::make_pair(
                        i->m_file, i->m_block_position
                    );
                    
                    block_positions[position] = i;

                    for (auto & j : blk.transactions())
                    {
                        if (
                            globals::instance().state() >=
                            globals::state_stopping
                            )
                        {
                            log_debug(
                                "DB TX load is aborting, state >= "
                                "state_stopping."
                            );
                            
                            return false;
                        }
                        
                        /**
                         * Get the hash of the transaction.
                         */
                        auto hash_tx = j.get_hash();
                        
                        transaction_index tx_index;

                        if (read_transaction_index(hash_tx, tx_index))
                        {
                            /**
                             * Check transaction hashes.
                             */
                            if (
                                check_level > 2 ||
                                i->file() != tx_index.get_transaction_position(
                                ).file_index() ||
                                i->block_position() !=
                                tx_index.get_transaction_position(
                                ).block_position()
                                )
                            {
                                /**
                                 * Either an error or a duplicate transaction.
                                 */
                                transaction tx_found;

                                if (
                                    tx_found.read_from_disk(
                                    tx_index.get_transaction_position()
                                    ) == false
                                    )
                                {
                                    log_debug(
                                        "DB TX cannot read mislocated "
                                        "transaction " <<
                                        hash_tx.to_string() << "."
                                    );

                                    /**
                                     * Fork
                                     */
                                    index_fork = i->block_index_previous();
                                }
                                else if (tx_found.get_hash() != hash_tx)
                                {
                                    log_debug(
                                        "DB TX invalid transaction "
                                        "position for transaction " <<
                                        tx_found.get_hash().to_string() <<
                                        ":" << hash_tx.to_string() << "."
                                    );

                                    /**
                                     * Fork
                                     */
                                    index_fork = i->block_index_previous();
                                }
                            }
                        }
                        
                        /**
                         * Check whether spent transaction outs were spent
                         * within the main chain.
                         */
                        std::uint32_t output = 0;
                        
                        if (check_level > 3)
                        {
                            for (auto & k : tx_index.spent())
                            {
                                if (k.is_null() == false)
                                {
                                    auto find = std::make_pair(
                                        k.file_index(), k.block_position()
                                    );
                                    
                                    if (block_positions.count(find) == 0)
                                    {
                                        log_error(
                                            "DB TX found bad spend at " <<
                                            i->m_height << "."
                                        );

                                        index_fork =
                                            i->block_index_previous()
                                        ;
                                    }
                                    
                                    /**
                                     * Check level 6 checks if spent transaction
                                     * outs were spent by a valid transaction
                                     * that consume them.
                                     */
                                    if (check_level > 5)
                                    {
                                        transaction tx_spend;
                                        
                                        if (tx_spend.read_from_disk(k) == false)
                                        {
                                            log_error(
                                                "DB TX cannot read spending "
                                                "transaction " <<
                                                hash_tx.to_string() << ":" <<
                                                output << " from disk."
                                            );

                                            index_fork =
                                                i->block_index_previous()
                                            ;
                                        }
                                        else if (tx_spend.check() == false)
                                        {
                                            log_error(
                                                "DB TX got invalid spending "
                                                "transaction " <<
                                                hash_tx.to_string() << ":" <<
                                                output << "."
                                            );

                                            index_fork =
                                                i->block_index_previous()
                                            ;
                                        }
                                        else
                                        {
                                            bool found = false;
                                            
                                            for (
                                                auto & l :
                                                tx_spend.transactions_in()
                                                )
                                            {
                                                if (
                                                    l.previous_out().get_hash()
                                                    == hash_tx &&
                                                    l.previous_out().n()
                                                    == output
                                                    )
                                                {
                                                    found = true;
                                                    
                                                    break;
                                                }
                                            }
                                            
                                            if (found == false)
                                            {
                                                log_error(
                                                    "DB TX spending "
                                                    "transaction " <<
                                                    hash_tx.to_string() <<
                                                    ":" << output << " does "
                                                    "not spend it."
                                                );

                                                index_fork =
                                                    i->block_index_previous()
                                                ;
                                            }
                                        }
                                    }
                                }
                                
                                output++;
                            }
                        }
                        
                        /**
                         * Check level 5 checks if all previous outs are
                         * marked spent.
                         */
                        if (check_level > 4)
                        {
                            for (auto & k : j.transactions_in())
                            {
                                transaction_index tx_index;
                                
                                if (
                                    read_transaction_index(
                                    k.previous_out().get_hash(), tx_index)
                                    )
                                {
                                    if (
                                        tx_index.spent().size() - 1 <
                                        k.previous_out().n() ||
                                        tx_index.spent()[
                                        k.previous_out().n()].is_null()
                                        )
                                    {
                                        log_error(
                                            "DB TX found unspent previous "
                                            "out " <<
                                            k.previous_out().get_hash().to_string()
                                            << ":" << k.previous_out().n() <<
                                            " in " << hash_tx.to_string() << "."
                                        );
                                        
                                        index_fork = i->block_index_previous();
                                    }
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                log_error("Block failed to read block from disk.");
            
                return false;
            }
        }

        if (index_fork)
        {
            log_info(
                "DB TX is moving best chain pointer back to block " <<
                index_fork->m_height << "."
            );
            
            block b;
            
            if (b.read_from_disk(index_fork) == false)
            {
                log_error("Block failed to read (index fork) block from disk.");
            
                return false;
            }
            
            /**
             * Allocate the db_tx.
             */
            db_tx dbtx;
            
            /**
             * Set the best chain.
             */
            b.set_best_chain(dbtx, index_fork);
        }
        
        return true;
    }
    
    return false;
}