bool leveldb_chain_keeper::end_slice(size_t slice_begin_index, block_detail_list& sliced_blocks) { leveldb_transaction_batch batch; leveldb_iterator it(db_.block->NewIterator(leveldb::ReadOptions())); data_chunk raw_depth = uncast_type(slice_begin_index); for (it->Seek(slice(raw_depth)); it->Valid(); it->Next()) { block_detail_ptr sliced_block = reconstruct_block(common_, it->value().ToString()); if (!sliced_block) return false; // Add to list of sliced blocks sliced_blocks.push_back(sliced_block); // Make sure to delete hash secondary index too. const hash_digest& block_hash = sliced_block->hash(); // Delete block header... batch.block.Delete(it->key()); // And it's secondary index. batch.block_hash.Delete(slice_block_hash(block_hash)); // Remove txs + spends + addresses too const auto& transactions = sliced_block->actual().transactions; for (const transaction_type& block_tx: transactions) if (!clear_transaction_data(batch, block_tx)) return false; } leveldb::WriteOptions options; // Execute batches. db_.write(batch); return true; }
std::error_code organizer_impl::verify(size_t fork_index, const block_detail_list& orphan_chain, size_t orphan_index) { BITCOIN_ASSERT(orphan_index < orphan_chain.size()); const auto& current_block = orphan_chain[orphan_index]->actual(); const size_t height = fork_index + orphan_index + 1; BITCOIN_ASSERT(height != 0); validate_block_impl validate(interface_, fork_index, orphan_chain, orphan_index, height, current_block, checkpoints_); auto code = validate.check_block(); if (code) return code; code = validate.accept_block(); if (code) return code; // Skip strict validation if above last checkpoint. if (fork_index > checkpoints_.last()) code = validate.connect_block(); return code; }
std::error_code leveldb_organizer::verify(int fork_index, const block_detail_list& orphan_chain, int orphan_index) { BITCOIN_ASSERT(orphan_index < orphan_chain.size()); const block_type& current_block = orphan_chain[orphan_index]->actual(); size_t depth = fork_index + orphan_index + 1; BITCOIN_ASSERT(depth != 0); leveldb_validate_block validate(common_, fork_index, orphan_chain, orphan_index, depth, current_block); return validate.start(); }
std::error_code organizer_impl::verify(size_t fork_point, const block_detail_list& orphan_chain, size_t orphan_index) { BITCOIN_ASSERT(orphan_index < orphan_chain.size()); const auto& current_block = orphan_chain[orphan_index]->actual(); const size_t height = fork_point + orphan_index + 1; BITCOIN_ASSERT(height != 0); validate_block_impl validate(interface_, fork_point, orphan_chain, orphan_index, height, current_block, checkpoints_); // Checks that are independent of the chain. auto ec = validate.check_block(); if (ec) return ec; // Checks that are dependent on height and preceding blocks. ec = validate.accept_block(); if (ec) return ec; // Start strict validation if past last checkpoint. if (strict(fork_point)) { const auto total_inputs = count_inputs(current_block); const auto total_transactions = current_block.transactions.size(); log_info(LOG_BLOCKCHAIN) << "Block [" << height << "] verify (" << total_transactions << ") txs and (" << total_inputs << ") inputs"; // Time this for logging. const auto timed = [&ec, &validate]() { // Checks that include input->output traversal. ec = validate.connect_block(); }; // Execute the timed validation. const auto elapsed = timer<std::chrono::milliseconds>::duration(timed); const auto ms_per_block = static_cast<float>(elapsed.count()); const auto ms_per_input = ms_per_block / total_inputs; const auto secs_per_block = ms_per_block / 1000; const auto verified = ec ? "unverified" : "verified"; log_info(LOG_BLOCKCHAIN) << "Block [" << height << "] " << verified << " in (" << secs_per_block << ") secs or (" << ms_per_input << ") ms/input"; } return ec; }
bool simple_chain_impl::release(size_t begin_index, block_detail_list& released_blocks) { const auto last_height = interface_.blocks.last_height(); BITCOIN_ASSERT(last_height != block_database::null_height); BITCOIN_ASSERT_MSG(begin_index > 0, "This loop will underflow."); for (size_t height = last_height; height >= begin_index; --height) { const auto block = std::make_shared<block_detail>(interface_.pop()); released_blocks.push_back(block); } return true; }
bool leveldb_chain_keeper::end_slice(size_t slice_begin_index, block_detail_list& sliced_blocks) { leveldb::WriteBatch blk_batch, blk_hash_batch; leveldb_transaction_batch tx_batch; leveldb_iterator it(db_blocks_->NewIterator(leveldb::ReadOptions())); data_chunk raw_depth = uncast_type(slice_begin_index); for (it->Seek(slice(raw_depth)); it->Valid(); it->Next()) { std::stringstream ss; ss.str(it->value().ToString()); protobuf::Block proto_block; proto_block.ParseFromIstream(&ss); // Convert protobuf block header into actual block block_type sliced_block; if (!reconstruct_block(common_, proto_block, sliced_block)) return false; // Add to list of sliced blocks block_detail_ptr sliced_detail = std::make_shared<block_detail>(sliced_block); sliced_blocks.push_back(sliced_detail); // Make sure to delete hash secondary index too. hash_digest block_hash = hash_block_header(sliced_block); // Delete block header... blk_batch.Delete(it->key()); // And it's secondary index. blk_hash_batch.Delete(slice_block_hash(block_hash)); // Remove txs + spends + addresses too for (const transaction_type& block_tx: sliced_block.transactions) if (!clear_transaction_data(tx_batch, block_tx)) return false; } leveldb::WriteOptions options; // Execute batches. db_blocks_->Write(options, &blk_batch); db_blocks_hash_->Write(options, &blk_hash_batch); db_txs_->Write(options, &tx_batch.tx_batch); db_spends_->Write(options, &tx_batch.spends_batch); db_address_->Write(options, &tx_batch.address_batch); return true; }
std::error_code leveldb_organizer::verify(size_t fork_index, const block_detail_list& orphan_chain, size_t orphan_index) { BITCOIN_ASSERT(orphan_index < orphan_chain.size()); const block_type& current_block = orphan_chain[orphan_index]->actual(); size_t height = fork_index + orphan_index + 1; BITCOIN_ASSERT(height != 0); leveldb_validate_block validate(common_, fork_index, orphan_chain, orphan_index, height, current_block); // Perform checks. std::error_code ec; ec = validate.check_block(); if (ec) return ec; ec = validate.accept_block(); if (ec) return ec; // Skip non-essential checks if before last checkpoint. if (fork_index < 278702) return std::error_code(); // Perform strict but slow tests - connect_block() return validate.connect_block(); }