void block_database::store(const block_type& block)
{
    const uint32_t height = index_.count();
    const auto number_txs = block.transactions.size();
    const uint32_t number_txs32 = static_cast<uint32_t>(number_txs);

    // Write block data.
    const auto write = [&](uint8_t* data)
    {
        satoshi_save(block.header, data);
        auto serial = make_serializer(data + 80);
        serial.write_4_bytes(height);
        serial.write_4_bytes(number_txs32);
        for (const auto& tx: block.transactions)
        {
            const auto tx_hash = hash_transaction(tx);
            serial.write_hash(tx_hash);
        }
    };

    const auto key = hash_block_header(block.header);
    const auto value_size = 80 + 4 + 4 + number_txs * hash_size;
    const auto position = map_.store(key, write, value_size);

    // Write height -> position mapping.
    write_position(position);
}
예제 #2
0
void bdb_blockchain::do_store(const message::block& stored_block,
    store_block_handler handle_store)
{
    block_detail_ptr stored_detail =
        std::make_shared<block_detail>(stored_block);
    int depth = chain_->find_index(hash_block_header(stored_block));
    if (depth != -1)
    {
        handle_store(error::duplicate,
            block_info{block_status::confirmed, depth});
        return;
    }
    if (!orphans_->add(stored_detail))
    {
        handle_store(error::duplicate,
            block_info{block_status::orphan, 0});
    }
    organize_->start();
    handle_store(stored_detail->errc(), stored_detail->info());
    // Every N blocks, we flush database
    static size_t flush_counter = 0;
    if (++flush_counter == 2000)
    {
        env_->txn_checkpoint(0, 0, 0);
        flush_counter = 0;
    }
}
예제 #3
0
int get_block_hash(Db*, const Dbt*, const Dbt* data, Dbt* second_key)
{
    std::stringstream ss(std::string(
        reinterpret_cast<const char*>(data->get_data()), data->get_size()));
    protobuf::Block proto_block;
    proto_block.ParseFromIstream(&ss);
    message::block serial_block = protobuf_to_block_header(proto_block);
    second_hash = hash_block_header(serial_block);
    second_key->set_data(second_hash.data());
    second_key->set_size(second_hash.size());
    return 0;
}
예제 #4
0
bool leveldb_common::save_block(
    uint32_t height, const block_type& serial_block)
{
    leveldb_transaction_batch batch;
    // Write block header + tx hashes
    data_chunk raw_block_data(
        80 + 4 + serial_block.transactions.size() * hash_digest_size);
    // Downcast to base header type so serializer selects that.
    auto header_end = satoshi_save(
        serial_block.header, raw_block_data.begin());
    BITCOIN_ASSERT(std::distance(raw_block_data.begin(), header_end) == 80);
    auto serial_hashes = make_serializer(header_end);
    // Write the number of transactions...
    serial_hashes.write_4_bytes(serial_block.transactions.size());
    // ... And now the tx themselves.
    for (uint32_t tx_index = 0;
        tx_index < serial_block.transactions.size(); ++tx_index)
    {
        const transaction_type& block_tx =
            serial_block.transactions[tx_index];
        const hash_digest& tx_hash = hash_transaction(block_tx);
        if (!save_transaction(batch, height, tx_index, tx_hash, block_tx))
        {
            log_fatal(LOG_BLOCKCHAIN) << "Could not save transaction";
            return false;
        }
        serial_hashes.write_hash(tx_hash);
    }
    BITCOIN_ASSERT(serial_hashes.iterator() ==
        raw_block_data.begin() + 80 + 4 +
            serial_block.transactions.size() * hash_digest_size);
    data_chunk raw_height = uncast_type(height);
    hash_digest block_hash = hash_block_header(serial_block.header);
    // Write block header
    batch.block.Put(slice(raw_height), slice(raw_block_data));
    batch.block_hash.Put(slice_block_hash(block_hash), slice(raw_height));
    // Execute batches.
    db_.write(batch);
    // Sync stealth database.
    db_stealth_->sync(height);
    return true;
}
예제 #5
0
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;
}
void block_database::store(const block_type& block)
{
    const size_t height = index_.size();
    // Write block data.
    const hash_digest key = hash_block_header(block.header);
    const size_t number_txs = block.transactions.size();
    const size_t value_size = 80 + 4 + 4 + number_txs * hash_size;
    auto write = [&](uint8_t* data)
    {
        satoshi_save(block.header, data);
        auto serial = make_serializer(data + 80);
        serial.write_4_bytes(height);
        serial.write_4_bytes(number_txs);
        for (const transaction_type& tx: block.transactions)
        {
            const hash_digest tx_hash = hash_transaction(tx);
            serial.write_hash(tx_hash);
        }
    };
    const position_type position = map_.store(key, value_size, write);
    // Write height -> position mapping.
    write_position(position);
}