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();
}