/** * BitcoinBlockHeader.hpp */ #include #include #include "endian.h" #include "ee382n_bitcoin/bitcoin_block_header.hpp" #include "ee382n_bitcoin/sha256.h" BitcoinBlockHeader::BitcoinBlockHeader() : _header() {} void BitcoinBlockHeader::set_version(uint32_t version) { _header.block_header_u32.version[0] = htole32(version); } uint32_t BitcoinBlockHeader::get_version() const { return le32toh(_header.block_header_u32.version[0]); } void BitcoinBlockHeader::set_prev_block(const std::string& prev_block) { hex2bin(prev_block, _header.block_header_u8.prev_block); } void BitcoinBlockHeader::set_prev_block(uint8_t *prev_block) { memcpy(_header.block_header_u8.prev_block, prev_block, 32); } std::string BitcoinBlockHeader::get_prev_block_str() const { return bin2hex(_header.block_header_u8.prev_block, 32);; } const uint8_t* BitcoinBlockHeader::get_prev_block_u8() const { return _header.block_header_u8.prev_block; } void BitcoinBlockHeader::set_merkle_root(const std::string& merkle_root) { hex2bin(merkle_root, _header.block_header_u8.merkle_root); } void BitcoinBlockHeader::set_merkle_root(uint8_t *merkle_root) { memcpy(_header.block_header_u8.merkle_root, merkle_root, 32); } std::string BitcoinBlockHeader::get_merkle_root_str() const { return bin2hex(_header.block_header_u8.merkle_root, 32); } const uint8_t* BitcoinBlockHeader::get_merkle_root_u8() const { return _header.block_header_u8.merkle_root; } void BitcoinBlockHeader::set_ntime(uint32_t ntime) { _header.block_header_u32.ntime[0] = htole32(ntime); } uint32_t BitcoinBlockHeader::get_ntime() const { return le32toh(_header.block_header_u32.ntime[0]); } void BitcoinBlockHeader::set_nbits(uint32_t nbits) { _header.block_header_u32.nbits[0] = htole32(nbits); } uint32_t BitcoinBlockHeader::get_nbits() const { return le32toh(_header.block_header_u32.nbits[0]); } void BitcoinBlockHeader::set_nonce(uint32_t nonce) { _header.block_header_u32.nonce[0] = htole32(nonce); } uint32_t BitcoinBlockHeader::get_nonce() const { return le32toh(_header.block_header_u32.nonce[0]); } std::ostream &operator<<(std::ostream &os, const BitcoinBlockHeader &header) { os << "BlockHeader { version: " << header.get_version() << ", prev_blockhash: " << header.get_prev_block_str() << ", merkle_root: " << header.get_merkle_root_str() << ", time: " << header.get_ntime() << ", bits: " << header.get_nbits() << ", nonce: " << header.get_nonce() << " }"; return os; } /** * Convert "big endian" hex-formatted string to correct little endian byte array * TODO: Make this safer - possibly add param to check size of output? * @param hex_str * @param out */ void BitcoinBlockHeader::hex2bin(const std::string &hex_str, uint8_t *out) { size_t size_bytes = hex_str.length()/2; for(int i = 0; i < hex_str.length(); i+=2) { std::string byte_str = hex_str.substr(i, 2); out[size_bytes - i/2 - 1] = (uint8_t) strtol(byte_str.c_str(), NULL, 16); } } /** * Convert "little endian" byte array into "big endian" hex-formatted string * @param bin Input * @param len Length of input in bytes * @return */ std::string BitcoinBlockHeader::bin2hex(const uint8_t *bin, size_t len) { std::stringstream stream; for(int i = len - 1; i >= 0 ; i--) { stream << std::setfill('0') << std::setw(2) << std::hex << static_cast(bin[i]); } return stream.str(); } BitcoinBlockHeader BitcoinBlockHeader::GenesisBlock() { BitcoinBlockHeader header; header.set_version(0x00000001); header.set_prev_block("0000000000000000000000000000000000000000000000000000000000000000"); header.set_merkle_root("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"); header.set_ntime(0x495fab29); header.set_nbits(0x1d00ffff); header.set_nonce(0x7c2bac1d); return header; } std::string BitcoinBlockHeader::hash() const { uint8_t hash_bytes[32]; sha256_double(_header.bytes, 80, hash_bytes); return bin2hex(hash_bytes, 32); } const uint8_t* BitcoinBlockHeader::header_bytes() const { return _header.bytes; }