probe_manager::probe_manager(stack_impl & owner) : stack_impl_(owner) , timer_(owner.io_service()) , timer_post_(owner.io_service()) , timer_probe_(owner.io_service()) { // ... }
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) { // ... }
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()) { // ... }
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; }