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); }
bool validate_block::coinbase_height_match() { // There are old blocks with version incorrectly set to 2. Ignore them. if (height_ < 237370) return true; // Checks whether the block height is in the coinbase // transaction input script. // Version 2 blocks and onwards. BITCOIN_ASSERT(current_block_.header.version >= 2); BITCOIN_ASSERT(current_block_.transactions.size() > 0); BITCOIN_ASSERT(current_block_.transactions[0].inputs.size() > 0); // First get the serialized coinbase input script as a series of bytes. const script_type& coinbase_script = current_block_.transactions[0].inputs[0].script; const data_chunk raw_coinbase = save_script(coinbase_script); // Try to recreate the expected bytes. big_number expect_number; expect_number.set_int64(height_); script_type expect_coinbase; expect_coinbase.push_operation({opcode::special, expect_number.data()}); // Save the expected coinbase script. const data_chunk expect = save_script(expect_coinbase); // Perform comparison of the first bytes with raw_coinbase. BITCOIN_ASSERT(expect.size() <= raw_coinbase.size()); return std::equal(expect.begin(), expect.end(), raw_coinbase.begin()); }
BC_API void obelisk_codec::message(const data_chunk& data, bool more) { switch (next_part_) { case command_part: wip_message_.command = std::string(data.begin(), data.end()); break; case id_part: if (4 != data.size()) { next_part_ = error_part; break; } wip_message_.id = from_little_endian<uint32_t>(data.begin(), data.end()); break; case payload_part: wip_message_.payload = data; break; case error_part: break; } if (!more) { if (next_part_ == payload_part) receive(wip_message_); else on_unknown_(wip_message_.command); next_part_ = command_part; } else if (next_part_ < error_part) next_part_ = static_cast<message_part>(next_part_ + 1); }
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); }
void wrap_fetch_transaction_args(data_chunk& data, const hash_digest& tx_hash) { data.resize(hash_digest_size); auto serial = make_serializer(data.begin()); serial.write_hash(tx_hash); BITCOIN_ASSERT(serial.iterator() == data.end()); }
script parse_script(const data_chunk& raw_script) { script script_object; for (auto it = raw_script.begin(); it != raw_script.end(); ++it) { byte raw_byte = *it; operation op; op.code = static_cast<opcode>(raw_byte); // raw_byte is unsigned so it's always >= 0 if (raw_byte <= 75) op.code = opcode::special; size_t read_n_bytes = number_of_bytes_from_opcode(op.code, raw_byte); for (size_t byte_count = 0; byte_count < read_n_bytes; ++byte_count) { ++it; if (it == raw_script.cend()) { log_warning() << "Premature end of script."; return script(); } op.data.push_back(*it); } script_object.push_operation(op); } return script_object; }
std::string encode_base58(const data_chunk& unencoded) { size_t leading_zeros = count_leading_zeros(unencoded); // size = log(256) / log(58), rounded up. const size_t number_nonzero = unencoded.size() - leading_zeros; const size_t indexes_size = number_nonzero * 138 / 100 + 1; // Allocate enough space in big-endian base58 representation. data_chunk indexes(indexes_size); // Process the bytes. for (auto it = unencoded.begin() + leading_zeros; it != unencoded.end(); ++it) { pack_value(indexes, *it); } // Skip leading zeroes in base58 result. auto first_nonzero = search_first_nonzero(indexes); // Translate the result into a string. std::string encoded; const size_t estimated_size = leading_zeros + (indexes.end() - first_nonzero); encoded.reserve(estimated_size); encoded.assign(leading_zeros, '1'); // Set actual main bytes. for (auto it = first_nonzero; it != indexes.end(); ++it) { const size_t index = *it; encoded += base58_chars[index]; } return encoded; }
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; }
data_chunk read_ephemkey(const data_chunk& stealth_data) { // Read ephemkey BITCOIN_ASSERT(stealth_data.size() == 1 + 4 + 33); data_chunk ephemkey(stealth_data.begin() + 5, stealth_data.end()); BITCOIN_ASSERT(ephemkey.size() == 33); return ephemkey; }
void BIO::Write(const data_chunk& data2wr) const { unsigned int written = 0; do { data_chunk tmp; tmp.insert(tmp.end(), data2wr.begin() + written, data2wr.end()); written += doWrite(tmp, written); } while(written < data2wr.size()); }
bool read_hash(hash_digest& hash, const data_chunk& raw_hash) { if (raw_hash.size() != hash.size()) { log_warning(LOG_SUBSCRIBER) << "Wrong size for hash. Dropping."; return false; } std::copy(raw_hash.begin(), raw_hash.end(), hash.begin()); return true; }
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()); }
record_type get_record(htdb_record_header& header, record_allocator& alloc, const data_chunk& key_data) { typedef byte_array<N> hash_type; htdb_record<hash_type> ht(header, alloc, "test"); hash_type key; BITCOIN_ASSERT(key.size() == key_data.size()); std::copy(key_data.begin(), key_data.end(), key.begin()); return ht.get(key); }
bool payment_address::set_encoded(const std::string& encoded_address) { const data_chunk decoded_address = decode_base58(encoded_address); // version + 20 bytes short hash + 4 bytes checksum if (decoded_address.size() != 25) return false; const uint8_t version = decoded_address[0]; if (!set_version(version)) return false; const data_chunk checksum_bytes( decoded_address.end() - 4, decoded_address.end()); // version + short hash const data_chunk main_body( decoded_address.begin(), decoded_address.end() - 4); // verify checksum bytes if (generate_sha256_checksum(main_body) != cast_chunk<uint32_t>(checksum_bytes)) return false; std::copy(main_body.begin() + 1, main_body.end(), hash_.begin()); return true; }
void address_subscriber::decode_reply( const data_chunk& data, const worker_uuid& worker, subscribe_handler handle_subscribe) { std::error_code ec; BITCOIN_ASSERT(data.size() == 4); auto deserial = make_deserializer(data.begin(), data.end()); if (!read_error_code(deserial, data.size(), ec)) return; BITCOIN_ASSERT(deserial.iterator() == data.end()); handle_subscribe(ec, worker); }
void address_subscriber::receive_update( const data_chunk& data, const worker_uuid& worker) { // Deserialize data -> address, height, block hash, tx constexpr size_t info_size = 1 + short_hash_size + 4 + hash_digest_size; auto deserial = make_deserializer(data.begin(), data.begin() + info_size); // [ addr,version ] (1 byte) uint8_t version_byte = deserial.read_byte(); // [ addr.hash ] (20 bytes) short_hash addr_hash = deserial.read_short_hash(); payment_address address(version_byte, addr_hash); // [ height ] (4 bytes) uint32_t height = deserial.read_4_bytes(); // [ block_hash ] (32 bytes) const hash_digest blk_hash = deserial.read_hash(); // [ tx ] BITCOIN_ASSERT(deserial.iterator() == data.begin() + info_size); transaction_type tx; satoshi_load(deserial.iterator(), data.end(), tx); post_updates(address, worker, height, blk_hash, tx); }
void BIO::WriteWithRetry(const data_chunk& data2wr) const { unsigned int written = 0; do { try { data_chunk tmp; tmp.insert(tmp.end(), data2wr.begin() + written, data2wr.end()); written += doWrite(tmp, written); } catch (RecoverableException& ex) { } } while (written < data2wr.size()); }
void attempt_load(const data_chunk& stream) const { Message result; try { satoshi_load(stream.begin(), stream.end(), result); handle_load_(std::error_code(), result); } catch (end_of_stream) { handle_load_(error::bad_stream, Message()); } }
HashType generate_hmac(const data_chunk& key, const data_chunk& data, std::function<HashType (const data_chunk&)> hash_func) { typedef typename HashType::value_type hash_char; std::array<hash_char, block_size> fixed_key; // Zero out std::fill(fixed_key.begin(), fixed_key.end(), 0); // Now copy key or hash into zeroed out buffer if (key.size() <= block_size) { std::copy(key.begin(), key.end(), fixed_key.begin()); } else { HashType fixed_key_digest = hash_func(key); BITCOIN_ASSERT(fixed_key.size() >= fixed_key_digest.size()); std::copy(fixed_key_digest.begin(), fixed_key_digest.end(), fixed_key.begin()); } // hash(o_key_pad + hash(i_key_pad + data)) // Work on inner section first data_chunk inner_data(fixed_key.size() + data.size()); // xor each digit of key... std::transform(fixed_key.begin(), fixed_key.end(), inner_data.begin(), [](hash_char digit) { return digit ^ 0x36; }); // ... and append the data. std::copy(data.begin(), data.end(), inner_data.begin() + fixed_key.size()); HashType inner_hash = hash_func(inner_data); // Work on outer section data_chunk outer_data(fixed_key.size() + inner_hash.size()); // xor each digit of key... std::transform(fixed_key.begin(), fixed_key.end(), outer_data.begin(), [](hash_char digit) { return digit ^ 0x5c; }); // ... and combine with inner_hash to get outer_data. std::copy(inner_hash.begin(), inner_hash.end(), outer_data.begin() + fixed_key.size()); return hash_func(outer_data); }
void attempt_load(const data_chunk& stream) const { Message result; try { satoshi_load(stream.begin(), stream.end(), result); handle_load_(error::success, result); } catch (bc::end_of_stream) { // This doesn't invalidate the channel (unlike the invalid header). handle_load_(bc::error::bad_stream, Message()); } }
int mmr_lookup(const data_chunk& key_data, const size_t value_size, const std::string& map_filename, const std::string& rows_filename) { typedef byte_array<KeySize> hash_type; hash_type key; BITCOIN_ASSERT(key.size() == key_data.size()); std::copy(key_data.begin(), key_data.end(), key.begin()); memory_map ht_file(map_filename); BITCOIN_ASSERT(ht_file.open()); record_hash_table_header header(ht_file, buckets); auto result = header.start(); BITCOIN_ASSERT(result); const auto record_size = hash_table_multimap_record_size<hash_type>(); BITCOIN_ASSERT(record_size == KeySize + 4 + 4); const auto header_size = record_hash_table_header_size(header.size()); const file_offset records_start = header_size; record_manager ht_manager(ht_file, records_start, record_size); result = ht_manager.start(); BITCOIN_ASSERT(result); memory_map lrs_file(rows_filename); BITCOIN_ASSERT(lrs_file.open()); const auto lrs_record_size = record_list_offset + value_size; record_manager lrs_manager(lrs_file, 0, lrs_record_size); result = lrs_manager.start(); BITCOIN_ASSERT(result); record_list lrs(lrs_manager); record_hash_table<hash_type> ht(header, ht_manager); record_multimap<hash_type> multimap(ht, lrs); record_multimap_iterable container(lrs, multimap.lookup(key)); for (const array_index index: container) { std::cout << "Index: " << index << std::endl; const auto memory = lrs_manager.get(index); const auto record = REMAP_ADDRESS(memory) + record_list_offset; const data_chunk data(record, record + value_size); std::cout << encode_base16(data) << std::endl; std::cout << std::endl; } return 0; }
bool payment_address::set_encoded(const std::string& encoded_address) { if (!is_base58(encoded_address)) return false; const data_chunk decoded_address = decode_base58(encoded_address); // version + 20 bytes short hash + 4 bytes checksum if (decoded_address.size() != 25) return false; if (!verify_checksum(decoded_address)) return false; version_ = decoded_address[0]; std::copy_n(decoded_address.begin() + 1, hash_.size(), hash_.begin()); return true; }
bool deserialize_address(payment_address& addr, const data_chunk& data) { auto deserial = make_deserializer(data.begin(), data.end()); try { uint8_t version_byte = deserial.read_byte(); short_hash hash = deserial.read_short_hash(); addr.set(version_byte, hash); } catch (end_of_stream) { return false; } if (deserial.iterator() != data.end()) return false; return true; }
T cast_chunk(data_chunk chunk, bool reverse=false) { #ifdef BOOST_LITTLE_ENDIAN reverse = !reverse; #elif BOOST_BIG_ENDIAN // do nothing #else #error "Endian isn't defined!" #endif if (reverse) std::reverse(chunk.begin(), chunk.end()); T val = 0; for (size_t i = 0; i < sizeof(T); ++i) val += static_cast<T>(chunk[i]) << (i*8); return val; }
void StringMessage::doDeserializeChunk(const data_chunk& data) { this->append(data.begin(), data.end()); size_t found = this->find(itsTerminator); if (std::string::npos != found) { // Terminator was found in data size_t remains_pos = found + itsTerminator.size(); data_chunk remains(this->begin() + remains_pos, this->end()); this->erase(this->begin() + remains_pos, this->end()); DeserializingComplete(remains); DBG << "Completed string with " << this->size() << "B (" << found << " + " << itsTerminator.size() << ")" << std::endl; } else { // Terminator was not found in data DBG << "Continuing, " << this->size() << "B so far" << std::endl; } }
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; }
std::string encode_base58(const data_chunk& unencoded_data) { std::string encoded_data; // Expected size increase from base58 conversion is approximately 137% // use 138% to be safe encoded_data.reserve((unencoded_data.size() - 1) * 138 / 100 + 1); // Convert big endian data to little endian // Extra zero at the end make sure bignum will interpret // as a positive number data_chunk tmp_data(unencoded_data.size() + 1, 0); std::reverse_copy(unencoded_data.begin(), unencoded_data.end(), tmp_data.begin()); big_number long_value; long_value.set_data(tmp_data); while (long_value > 0) { auto result = divmod(long_value, 58); long_value = result.first; size_t remainder = result.second.uint32(); encoded_data += base58_chars[remainder]; } // Leading zeroes encoded as base58 zeros for (const uint8_t unencoded_byte: unencoded_data) { if (unencoded_byte != 0) break; encoded_data += base58_chars[0]; } // Convert little endian std::string to big endian reverse(encoded_data.begin(), encoded_data.end()); return encoded_data; }
// Construct from a stream object explicit shared_const_buffer(const data_chunk& user_data) : data(new std::vector<char>(user_data.begin(), user_data.end())), buffer(boost::asio::buffer(*data)) { }
bool verify_checksum(const data_chunk& data) { data_chunk body(data.begin(), data.end() - 4); auto checksum = from_little_endian<uint32_t>(data.end() - 4); return bitcoin_checksum(body) == checksum; }