Beispiel #1
0
BCW_API bool hd_private_key::set_serialized(std::string encoded)
{
    if (!is_base58(encoded))
        return false;
    const data_chunk decoded = decode_base58(encoded);
    if (decoded.size() != serialized_length)
        return false;
    if (!verify_checksum(decoded))
        return false;

    auto ds = make_deserializer(decoded.begin(), decoded.end());
    auto prefix = ds.read_big_endian<uint32_t>();
    if (prefix != mainnet_private_prefix && prefix != testnet_private_prefix)
        return false;

    valid_ = true;
    lineage_.testnet = prefix == testnet_private_prefix;
    lineage_.depth = ds.read_byte();
    lineage_.parent_fingerprint = ds.read_little_endian<uint32_t>();
    lineage_.child_number = ds.read_big_endian<uint32_t>();
    c_ = ds.read_bytes<chain_code_size>();
    ds.read_byte();
    k_ = ds.read_bytes<ec_secret_size>();
    K_ = secret_to_public_key(k_);
    return true;
}
Beispiel #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);
}
Beispiel #3
0
obj deserialize_as(const buf_t& buffer, obj result = obj())
{
    if (!buffer.empty())
        make_deserializer(buffer)(result);

    return result;
}
Beispiel #4
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);
}
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();
}
Beispiel #6
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();
}
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();
}
Beispiel #8
0
stealth_bitfield calculate_bitfield(const data_chunk& stealth_data)
{
    // Calculate stealth bitfield
    const hash_digest index = generate_sha256_hash(stealth_data);
    auto deserial = make_deserializer(
        index.begin(), index.begin() + bitfield_size);
    stealth_bitfield bitfield = deserial.read_uint_auto<stealth_bitfield>();
    return bitfield;
}
Beispiel #9
0
void receive_transaction_result(const data_chunk& data,
    blockchain::fetch_handler_transaction handle_fetch)
{
    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);
    transaction_type tx;
    satoshi_load(deserial.iterator(), data.end(), tx);
    handle_fetch(ec, tx);
}
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;
}
Beispiel #11
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;
}
Beispiel #12
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;
}
Beispiel #13
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;
}
Beispiel #14
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;
}
Beispiel #15
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};
}
Beispiel #16
0
bool hd_public_key::set_encoded(const std::string& encoded)
{
    data_chunk decoded;
    if (!decode_base58(decoded, encoded))
        return false;
    if (decoded.size() != serialized_length)
        return false;
    if (!verify_checksum(decoded))
        return false;

    auto ds = make_deserializer(decoded.begin(), decoded.end());
    auto prefix = ds.read_big_endian<uint32_t>();
    if (prefix != mainnet_public_prefix && prefix != testnet_public_prefix)
        return false;

    valid_ = true;
    lineage_.testnet = prefix == testnet_public_prefix;
    lineage_.depth = ds.read_byte();
    lineage_.parent_fingerprint = ds.read_little_endian<uint32_t>();
    lineage_.child_number = ds.read_big_endian<uint32_t>();
    c_ = ds.read_bytes<chain_code_size>();
    K_ = ds.read_data(33);
    return true;
}
Beispiel #17
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();
}