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); }
void stealth_database::modify_entries_count() { entries_count_ += entries_written_count_; uint8_t* item = file_.data() + 8; auto serial = make_serializer(item); serial.write_4_bytes(entries_count_); }
data_chunk create_spent_key(const Point& point) { data_chunk spent_key(hash_digest_size + 4); auto serial = make_serializer(spent_key.begin()); serial.write_hash(point.hash); serial.write_4_bytes(point.index); return spent_key; }
bool leveldb_common::save_transaction(leveldb_transaction_batch& batch, uint32_t block_height, uint32_t tx_index, const hash_digest& tx_hash, const transaction_type& block_tx) { if (duplicate_exists(tx_hash, block_height, tx_index)) return true; data_chunk tx_data(8 + satoshi_raw_size(block_tx)); // Serialize tx. auto serial = make_serializer(tx_data.begin()); serial.write_4_bytes(block_height); serial.write_4_bytes(tx_index); // Actual tx data. auto end_iter = satoshi_save(block_tx, serial.iterator()); BITCOIN_ASSERT( std::distance(tx_data.begin(), end_iter) == 8 + satoshi_raw_size(block_tx)); // Save tx to leveldb batch.tx.Put(slice(tx_hash), slice(tx_data)); // Add inputs to spends database. // Coinbase inputs do not spend anything. if (!is_coinbase(block_tx)) for (uint32_t input_index = 0; input_index < block_tx.inputs.size(); ++input_index) { const transaction_input_type& input = block_tx.inputs[input_index]; const input_point inpoint{tx_hash, input_index}; if (!mark_spent_outputs(batch.spend, input.previous_output, inpoint)) return false; if (!add_debit(batch.debit, input, {tx_hash, input_index}, block_height)) return false; } // Save address -> output mappings. for (uint32_t output_index = 0; output_index < block_tx.outputs.size(); ++output_index) { const transaction_output_type& output = block_tx.outputs[output_index]; if (!add_credit(batch.credit, output, {tx_hash, output_index}, block_height)) return false; } return true; }
void stealth_database::add_header_entry_index(uint32_t block_height) { const uint32_t interval = block_height; BITCOIN_ASSERT(interval < max_header_rows_); uint64_t offset = header_sector_ + interval * 4; uint8_t* iter = file_.data() + offset; auto serial = make_serializer(iter); serial.write_4_bytes(entries_count_); }
void wrap_fetch_history_args(data_chunk& data, const payment_address& address, size_t from_height) { data.resize(1 + short_hash_size + 4); auto serial = make_serializer(data.begin()); serial.write_byte(address.version()); serial.write_short_hash(address.hash()); serial.write_4_bytes(from_height); BITCOIN_ASSERT(serial.iterator() == data.end()); }
uint64_t addr_key_checksum(const output_point& outpoint) { data_chunk checksum_data(hash_digest_size + 4); auto serial = make_serializer(checksum_data.begin()); serial.write_hash(outpoint.hash); serial.write_4_bytes(outpoint.index); BITCOIN_ASSERT(serial.iterator() == checksum_data.end()); hash_digest hash = generate_sha256_hash(checksum_data); data_chunk raw_checksum(hash.begin(), hash.begin() + 8); return cast_chunk<uint64_t>(raw_checksum); }
uint32_t addr_key_checksum(const output_point& outpoint) { data_chunk chksum_data(hash_digest_size + 4); auto serial = make_serializer(chksum_data.begin()); serial.write_hash(outpoint.hash); serial.write_4_bytes(outpoint.index); BITCOIN_ASSERT( std::distance(chksum_data.begin(), serial.iterator()) == hash_digest_size + 4); return generate_sha256_checksum(chksum_data); }
bool add_credit(leveldb::WriteBatch& batch, const payment_address& address, uint64_t output_value, const output_point& outpoint, uint32_t block_height) { data_chunk addr_key = create_address_key(address, outpoint); // outpoint, value, block_height data_chunk row_info(36 + 8 + 4); auto serial = make_serializer(row_info.begin()); // outpoint serial.write_hash(outpoint.hash); serial.write_4_bytes(outpoint.index); // value serial.write_8_bytes(output_value); // block_height serial.write_4_bytes(block_height); BITCOIN_ASSERT( std::distance(row_info.begin(), serial.iterator()) == 36 + 8 + 4); batch.Put(slice(addr_key), slice(row_info)); return true; }
bool add_debit(leveldb::WriteBatch& batch, const transaction_input_type& input, const input_point& inpoint, uint32_t block_height) { payment_address address; // Not a Bitcoin address so skip this output. if (!extract(address, input.script)) return true; data_chunk addr_key = create_address_key(address, input.previous_output); // inpoint data_chunk row_info(36 + 4); auto serial = make_serializer(row_info.begin()); // inpoint serial.write_hash(inpoint.hash); serial.write_4_bytes(inpoint.index); // block_height serial.write_4_bytes(block_height); BITCOIN_ASSERT( std::distance(row_info.begin(), serial.iterator()) == 36 + 4); batch.Put(slice(addr_key), slice(row_info)); return true; }
data_chunk create_address_key( const payment_address& address, const output_point& outpoint) { data_chunk result(1 + short_hash_size + 4); auto serial = make_serializer(result.begin()); serial.write_byte(address.version()); serial.write_short_hash(address.hash()); serial.write_4_bytes(addr_key_checksum(outpoint)); BITCOIN_ASSERT( std::distance(result.begin(), serial.iterator()) == 1 + short_hash_size + 4); return result; }
void spend_database::store(const output_point& outpoint, const input_point& spend) { const auto write = [&spend](uint8_t* data) { auto serial = make_serializer(data); serial.write_data(spend.hash); serial.write_4_bytes(spend.index); }; const auto key = output_to_hash(outpoint); map_.store(key, write); }
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); }
void history_scan_database::add(const address_bitset& key, const uint8_t marker, const point_type& point, uint32_t block_height, uint64_t value) { BITCOIN_ASSERT(key.size() >= settings_.sharded_bitsize); // Both add() and sync() must have identical lookup of shards. hsdb_shard& shard = lookup(key); address_bitset sub_key = drop_prefix(key); BITCOIN_ASSERT(sub_key.size() == settings_.scan_bitsize()); #ifdef HSDB_DEBUG log_debug(LOG_HSDB) << "Sub key = " << sub_key; #endif data_chunk row_data(settings_.row_value_size); auto serial = make_serializer(row_data.begin()); serial.write_byte(marker); serial.write_hash(point.hash); serial.write_4_bytes(point.index); serial.write_4_bytes(block_height); serial.write_8_bytes(value); BITCOIN_ASSERT(serial.iterator() == row_data.begin() + settings_.row_value_size); shard.add(sub_key, row_data); }
index_type linked_records::insert(index_type next) { static_assert(sizeof(index_type) == sizeof(uint32_t), "index_type incorrect size"); // Create new record. index_type record = allocator_.allocate(); record_type data = allocator_.get(record); // Write next value at first 4 bytes of record. auto serial = make_serializer(data); serial.write_4_bytes(next); return record; }
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; }
void write_variable_uint(uint64_t value) { if (value < 0xfd) { write_byte(value); } else if (value <= 0xffff) { write_byte(0xfd); write_2_bytes(value); } else if (value <= 0xffffffff) { write_byte(0xfe); write_4_bytes(value); } else { write_byte(0xff); write_8_bytes(value); } }
void dec_prepare_output_file (FILE *fp) { if(putHeader(input_file_header, fp)){ ERROR("putHeader"); } uint32_t k = 0, **vector = NULL, *size_vector; vector = calloc(input_file_header->numChannels, sizeof(uint32_t *)); size_vector = calloc(input_file_header->numChannels, sizeof(uint32_t)); for(curr_channel=0; curr_channel<input_file_header->numChannels; curr_channel++) { size_vector[curr_channel] = b_to_uint32(&output_buffer[curr_channel], &vector[curr_channel], input_file_header->bitsPerSample, 0); } for (k=0; k<size_vector[0]; k++){ for(curr_channel=0; curr_channel<input_file_header->numChannels; curr_channel++) { switch (input_file_header->bitsPerSample/8){ case 1: if ( write_1_byte32(fp, &vector[curr_channel][k], input_file_header->endianness)){ printf("ERROR: io chunkSize\n"); }break; case 2: if (write_2_bytes32(fp, &vector[curr_channel][k], input_file_header->endianness)) { printf("ERROR: io chunkSize\n"); }break; case 3: if (write_3_bytes(fp, &vector[curr_channel][k], input_file_header->endianness)) { printf("ERROR: io chunkSize\n"); }break; case 4: if (write_4_bytes(fp, &vector[curr_channel][k], input_file_header->endianness)) { printf("ERROR: io chunkSize\n"); } } } } for(curr_channel=0; curr_channel<input_file_header->numChannels; curr_channel++) { /*bprint(&output_buffer[curr_channel]);*/ if(output_vector[curr_channel]) free(output_vector[curr_channel]); if(data_vector[curr_channel]) free(data_vector[curr_channel]); bdestroy(&output_buffer[curr_channel]); bdestroy(&data_buffer[curr_channel]); if(frequencies && frequencies[curr_channel]) free(frequencies[curr_channel]); if(vector[curr_channel]) free(vector[curr_channel]); } free(size_vector); free(vector); if(nbits_run) free(nbits_run); if(nbits_code) free(nbits_code); if(firsts) free(firsts); if(max_bits) free(max_bits); if(frequencies) free(frequencies); free(data_buffer); free(data_vector); free(output_buffer); free(output_vector); free(input_file_header); }
bool leveldb_common::save_transaction(leveldb_transaction_batch& batch, uint32_t block_height, uint32_t tx_index, const hash_digest& tx_hash, const transaction_type& block_tx) { if (is_special_duplicate(block_height, tx_index)) return true; data_chunk tx_data(8 + satoshi_raw_size(block_tx)); // Serialize tx. auto serial = make_serializer(tx_data.begin()); serial.write_4_bytes(block_height); serial.write_4_bytes(tx_index); // Actual tx data. auto end_iter = satoshi_save(block_tx, serial.iterator()); BITCOIN_ASSERT( tx_data.begin() + 8 + satoshi_raw_size(block_tx) == end_iter); // Save tx to leveldb batch.tx.Put(slice(tx_hash), slice(tx_data)); // Add inputs to spends database. // Coinbase inputs do not spend anything. if (!is_coinbase(block_tx)) for (uint32_t input_index = 0; input_index < block_tx.inputs.size(); ++input_index) { const transaction_input_type& input = block_tx.inputs[input_index]; const input_point inpoint{tx_hash, input_index}; if (!mark_spent_outputs(batch.spend, input.previous_output, inpoint)) return false; if (!add_debit(batch.debit, input, {tx_hash, input_index}, block_height)) return false; } // A stack of size 1. Keep the stealth_data from // one iteration to the next. data_chunk stealth_data_store; auto unload_stealth_store = [&]() { return std::move(stealth_data_store); }; // Save address -> output mappings. for (uint32_t output_index = 0; output_index < block_tx.outputs.size(); ++output_index) { const transaction_output_type& output = block_tx.outputs[output_index]; // If a stealth output then skip processing. if (process_stealth_output_info(output, stealth_data_store)) continue; data_chunk stealth_data = unload_stealth_store(); // Try to extract an address. payment_address address; if (!extract(address, output.script)) continue; // Process this output. if (!stealth_data.empty()) add_stealth_info(stealth_data, address, tx_hash, *db_stealth_); if (!add_credit(batch.credit, address, output.value, {tx_hash, output_index}, block_height)) return false; } return true; }