Esempio n. 1
0
hashtable_database_writer::hashtable_database_writer(mmfile& file)
  : file_(file)
{
    BITCOIN_ASSERT(file_.data() != nullptr);
    // [ version ]      8
    // [ buckets ]      8
    // [ values size ]  8
    //     ...
    //     ...
    BITCOIN_ASSERT(file_.size() > 24);
    auto deserial = make_deserializer(file_.data(), file_.data() + 24);
    version_ = deserial.read_8_bytes();
    buckets_ = deserial.read_8_bytes();
    total_records_size_ = deserial.read_8_bytes();
    BITCOIN_ASSERT(version_ == 1);
    const size_t header_size = 24 + buckets_ * 8;
    BITCOIN_ASSERT(file_.size() >= header_size + total_records_size_);
    // Advise the kernel that our access patterns for the tx records
    // will be random without pattern.
    //madvise(file_.data(), 24, POSIX_MADV_DONTNEED);
    //madvise(file_.data() + 24, buckets_ * 8,
    //    POSIX_MADV_WILLNEED | POSIX_MADV_RANDOM);
    //madvise(file_.data() + header_size, file_.size() - header_size,
    //    POSIX_MADV_DONTNEED | POSIX_MADV_RANDOM);
}
Esempio n. 2
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. 3
0
 network_address_type read_network_address()
 {
     network_address_type addr;
     addr.services = read_8_bytes();
     // Read IP address
     read_bytes<16>(iter_, end_, addr.ip);
     addr.port = read_data_impl<uint16_t>(iter_, end_, true);
     return addr;
 }
Esempio n. 4
0
uint64_t hashtable_database_writer::read_bucket_value(uint64_t bucket_index)
{
    BITCOIN_ASSERT(file_.size() > 24 + buckets_ * 8);
    BITCOIN_ASSERT(bucket_index < buckets_);
    uint8_t* bucket_begin = file_.data() + bucket_offset(bucket_index);
    // Read current record stored in the bucket.
    auto deserial = make_deserializer(bucket_begin, bucket_begin + 8);
    return deserial.read_8_bytes();
}
Esempio n. 5
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;
 }
Esempio n. 6
0
const hashtable_database_reader::get_result hashtable_database_reader::get(
    const hash_digest& key_hash) const
{
    uint64_t bucket_index = remainder(key_hash.data(), writer_.buckets());
    BITCOIN_ASSERT(bucket_index < writer_.buckets());
    uint64_t record_offset = read_record_offset(file_.data(), bucket_index);
    const uint64_t header_size = 24 + writer_.buckets() * 8;
    const uint8_t* all_records_begin = file_.data() + header_size;
    const uint8_t* all_records_end =
        all_records_begin + writer_.records_size();
    const uint8_t* record_begin = all_records_begin + record_offset;
    // We don't know the end of a record, so we use the end of all records
    // for the deserializer.
    // We will be jumping around the records since it's a chained
    // list per bucket.
    // Begin iterating the list.
    while (true)
    {
        auto deserial = make_deserializer(record_begin, all_records_end);
        const hash_digest current_hash = deserial.read_hash();
        uint64_t value_size = deserial.read_variable_uint();
        if (current_hash != key_hash)
        {
            // Move to next record in bucket.
            // Skip the transaction data.
            deserial.set_iterator(deserial.iterator() + value_size);
            uint64_t next_record = deserial.read_8_bytes();
            if (next_record == record_doesnt_exist)
                return {nullptr, nullptr};
            record_begin = all_records_begin + next_record;
            continue;
        }
        // We have the record!
        return {deserial.iterator(), deserial.iterator() + value_size};
    }
    BITCOIN_ASSERT_MSG(false, "Broke out of unbreakable loop!");
    return {nullptr, nullptr};
}
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. 8
0
uint64_t read_record_offset(const uint8_t* data, uint64_t bucket_index)
{
    const uint8_t* bucket_begin = data + bucket_offset(bucket_index);
    auto deserial = make_deserializer(bucket_begin, bucket_begin + 8);
    return deserial.read_8_bytes();
}