Esempio n. 1
0
void receive_history_result(const data_chunk& data,
    blockchain::fetch_handler_history handle_fetch)
{
    BITCOIN_ASSERT(data.size() >= 4);
    std::error_code ec;
    auto deserial = make_deserializer(data.begin(), data.end());
    if (!read_error_code(deserial, data.size(), ec))
        return;
    BITCOIN_ASSERT(deserial.iterator() == data.begin() + 4);
    size_t row_size = 36 + 4 + 8 + 36 + 4;
    if ((data.size() - 4) % row_size != 0)
    {
        log_error() << "Malformed response for *.fetch_history";
        return;
    }
    size_t number_rows = (data.size() - 4) / row_size;
    blockchain::history_list history(number_rows);
    for (size_t i = 0; i < history.size(); ++i)
    {
        blockchain::history_row& row = history[i];
        row.output.hash = deserial.read_hash();
        row.output.index = deserial.read_4_bytes();
        row.output_height = deserial.read_4_bytes();
        row.value = deserial.read_8_bytes();
        row.spend.hash = deserial.read_hash();
        row.spend.index = deserial.read_4_bytes();
        row.spend_height = deserial.read_4_bytes();
    }
    BITCOIN_ASSERT(deserial.iterator() == data.end());
    handle_fetch(ec, history);
}
Esempio n. 2
0
stealth_database::stealth_database(mmfile& file)
  : file_(file)
{
    BITCOIN_ASSERT(file_.data() != nullptr);
    // metadata:
    //   [ version:4 ]
    //   [ max_header_rows:4 ]
    //   [ entries_count:4 ]
    // header:
    //   [ ...               ]
    //   [ [ entry_index:4 ] ]
    //   [ ...               ]
    // entries:
    //   [ ...                                                            ]
    //   [ [ prefix_bitfield:4 ][ ephemkey:33 ][ address:21 ][ tx_id:32 ] ]
    //   [ ...                                                            ]
    BITCOIN_ASSERT(file_.size() > metadata_size);
    // Read off metadata.
    auto deserial = make_deserializer(
        file_.data(), file_.data() + metadata_size);
    version_ = deserial.read_4_bytes();
    max_header_rows_ = deserial.read_4_bytes();
    entries_count_ = deserial.read_4_bytes();
    BITCOIN_ASSERT(version_ == 1);
    // Calculate sector offsets.
    header_sector_ = metadata_size;
    entries_sector_ = header_sector_ + max_header_rows_ * 4;
    reset();
}
Esempio n. 3
0
uint32_t stealth_database::read_start_entry_index(uint32_t from_height)
{
    const uint32_t interval = from_height;
    BITCOIN_ASSERT(interval < max_header_rows_);
    uint64_t offset = header_sector_ + interval * 4;
    uint8_t* iter = file_.data() + offset;
    auto deserial = make_deserializer(iter, iter + 4);
    return deserial.read_4_bytes();
}
Esempio n. 4
0
bool leveldb_common::get_transaction(leveldb_tx_info& tx_info,
    const hash_digest& tx_hash, bool read_parent, bool read_tx)
{
    // First we try to read the bytes from the database.
    std::string value;
    leveldb::Status status = db_.tx->Get(
        leveldb::ReadOptions(), slice(tx_hash), &value);
    if (status.IsNotFound())
        return false;
    else if (!status.ok())
    {
        log_fatal(LOG_BLOCKCHAIN) << "get_transaction("
            << tx_hash << "): " << status.ToString();
        return false;
    }
    // Read the parent block height and our index in that block (if neccessary).
    BITCOIN_ASSERT(value.size() > 8);
    if (read_parent)
    {
        auto deserial = make_deserializer(value.begin(), value.begin() + 8);
        tx_info.height = deserial.read_4_bytes();
        tx_info.index = deserial.read_4_bytes();
    }
    if (!read_tx)
        return true;
    // Read the actual transaction (if neccessary).
    try
    {
        BITCOIN_ASSERT(value.size() > 8);
        satoshi_load(value.begin() + 8, value.end(), tx_info.tx);
    }
    catch (end_of_stream)
    {
        return false;
    }
    BITCOIN_ASSERT(satoshi_raw_size(tx_info.tx) + 8 == value.size());
    BITCOIN_ASSERT(hash_transaction(tx_info.tx) == tx_hash);
    return true;
}
void history_scan_database::scan(const address_bitset& key,
    read_function read_func, size_t from_height) const
{
    BITCOIN_ASSERT(key.size() >= settings_.sharded_bitsize);
    const hsdb_shard& shard = lookup(key);
    address_bitset sub_key = drop_prefix(key);
    auto read_wrapped = [&read_func](const uint8_t* data)
    {
        auto deserial = make_deserializer_unsafe(data);
        history_row row{
            // output or spend?
            marker_to_id(deserial.read_byte()),
            // point
            deserial.read_hash(),
            deserial.read_4_bytes(),
            // height
            deserial.read_4_bytes(),
            // value or checksum
            deserial.read_8_bytes()};
        read_func(row);
    };
    shard.scan(sub_key, read_wrapped, from_height);
}
Esempio n. 6
0
 uint64_t read_variable_uint()
 {
     uint8_t length = read_byte();
     uint64_t value = 0;
     if (length < 0xfd)
         value = length;
     else if (length == 0xfd)
         value += read_2_bytes();
     else if (length == 0xfe)
         value += read_4_bytes();
     else if (length == 0xff)
         value += read_8_bytes();
     return value;
 }
big_number leveldb_chain_keeper::end_slice_difficulty(size_t slice_begin_index)
{
    big_number total_work = 0;
    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())
    {
        constexpr size_t bits_offset = 4 + 2 * hash_digest_size + 4;
        BITCOIN_ASSERT(it->value().size() >= 84);
        // Deserialize only the bits field of block header.
        std::string raw_bits(it->value().data(), 4);
        auto deserial = make_deserializer(raw_bits.begin(), raw_bits.end());
        uint32_t bits = deserial.read_4_bytes();
        // Accumulate the total work.
        total_work += block_work(bits);
    }
    return total_work;
}
Esempio n. 8
0
bool unwrap(uint8_t& version, data_chunk& payload, uint32_t& checksum,
    data_slice wrapped)
{
    constexpr size_t version_length = sizeof(version);
    constexpr size_t checksum_length = sizeof(checksum);
    // guard against insufficient buffer length
    if (wrapped.size() < version_length + checksum_length)
        return false;
    if (!verify_checksum(wrapped))
        return false;
    // set return values
    version = wrapped.data()[0];
    payload = data_chunk(wrapped.begin() + version_length,
        wrapped.end() - checksum_length);
    const auto checksum_start = wrapped.end() - checksum_length;
    auto deserial = make_deserializer(checksum_start, wrapped.end());
    checksum = deserial.read_4_bytes();
    return true;
}
Esempio n. 9
0
bool leveldb_common::fetch_spend(const output_point& spent_output,
    input_point& input_spend)
{
    data_chunk spent_key = create_spent_key(spent_output);
    std::string raw_spend;
    leveldb::Status status = db_.spend->Get(
        leveldb::ReadOptions(), slice(spent_key), &raw_spend);
    if (status.IsNotFound())
        return false;
    else if (!status.ok())
    {
        log_fatal(LOG_BLOCKCHAIN) << "fetch_spend: " << status.ToString();
        return false;
    }
    const data_chunk raw_spend_data(raw_spend.begin(), raw_spend.end());
    auto deserial = make_deserializer(
        raw_spend_data.begin(), raw_spend_data.end());
    input_spend.hash = deserial.read_hash();
    input_spend.index = deserial.read_4_bytes();
    return true;
}
Esempio n. 10
0
bool leveldb_common::deserialize_block(leveldb_block_info& blk_info,
    const std::string& raw_data, bool read_header, bool read_tx_hashes)
{
    // Read the header (if neccessary).
    // There is always at least one tx in a block.
    BITCOIN_ASSERT(raw_data.size() >= 80 + 4 + hash_digest_size);
    BITCOIN_ASSERT((raw_data.size() - 84) % hash_digest_size == 0);
    if (read_header)
        satoshi_load(raw_data.begin(), raw_data.begin() + 80, blk_info.header);
    if (!read_tx_hashes)
        return true;
    // Read the tx hashes for this block (if neccessary).
    auto deserial = make_deserializer(raw_data.begin() + 80, raw_data.end());
    uint32_t tx_count = deserial.read_4_bytes();
    for (size_t i = 0; i < tx_count; ++i)
    {
        const hash_digest& tx_hash = deserial.read_hash();
        blk_info.tx_hashes.push_back(tx_hash);
    }
    return true;
}