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