Line data Source code
1 : // Copyright (c) 2009-2010 Satoshi Nakamoto 2 : // Copyright (c) 2009-2019 The Bitcoin Core developers 3 : // Distributed under the MIT software license, see the accompanying 4 : // file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 : 6 : #include <primitives/block.h> 7 : 8 : #include <hash.h> 9 : #include <hash_x11.h> 10 : #include <streams.h> 11 : #include <tinyformat.h> 12 : 13 1020111 : uint256 CBlockHeader::GetHash() const 14 : { 15 1020111 : std::vector<unsigned char> vch(80); 16 1020111 : CVectorWriter ss(SER_GETHASH, PROTOCOL_VERSION, vch, 0); 17 1020108 : ss << *this; 18 1020111 : return HashX11((const char *)vch.data(), (const char *)vch.data() + vch.size()); 19 1020117 : } 20 : 21 0 : std::string CBlock::ToString() const 22 : { 23 0 : std::stringstream s; 24 0 : s << strprintf("CBlock(hash=%s, ver=0x%08x, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u)\n", 25 0 : GetHash().ToString(), 26 0 : nVersion, 27 0 : hashPrevBlock.ToString(), 28 0 : hashMerkleRoot.ToString(), 29 0 : nTime, nBits, nNonce, 30 0 : vtx.size()); 31 0 : for (const auto& tx : vtx) { 32 0 : s << " " << tx->ToString() << "\n"; 33 : } 34 0 : return s.str(); 35 0 : } 36 : 37 0 : static void MarkVersionAsMostRecent(std::list<int32_t>& last_unique_versions, std::list<int32_t>::const_iterator version_it) 38 : { 39 0 : if (version_it != last_unique_versions.cbegin()) { 40 : // Move the found version to the front of the list 41 0 : last_unique_versions.splice(last_unique_versions.begin(), last_unique_versions, version_it, std::next(version_it)); 42 0 : } 43 0 : } 44 : 45 0 : static void SaveVersionAsMostRecent(std::list<int32_t>& last_unique_versions, const int32_t version) 46 : { 47 0 : last_unique_versions.push_front(version); 48 : 49 : // Always keep the last 7 unique versions 50 0 : constexpr std::size_t max_backwards_look_ups = 7; 51 0 : if (last_unique_versions.size() > max_backwards_look_ups) { 52 : // Evict the oldest version 53 0 : last_unique_versions.pop_back(); 54 0 : } 55 0 : } 56 : 57 0 : void CompressibleBlockHeader::Compress(const std::vector<CompressibleBlockHeader>& previous_blocks, std::list<int32_t>& last_unique_versions) 58 : { 59 0 : if (previous_blocks.empty()) { 60 : // Previous block not available, we have to send the block completely uncompressed 61 0 : SaveVersionAsMostRecent(last_unique_versions, nVersion); 62 0 : return; 63 : } 64 : 65 : // Try to compress version 66 0 : const auto version_it = std::find(last_unique_versions.cbegin(), last_unique_versions.cend(), nVersion); 67 0 : if (version_it != last_unique_versions.cend()) { 68 : // Version is found in the last 7 unique blocks. 69 0 : bit_field.SetVersionOffset(static_cast<uint8_t>(std::distance(last_unique_versions.cbegin(), version_it) + 1)); 70 : 71 : // Mark the version as the most recent one 72 0 : MarkVersionAsMostRecent(last_unique_versions, version_it); 73 0 : } else { 74 : // Save the version as the most recent one 75 0 : SaveVersionAsMostRecent(last_unique_versions, nVersion); 76 : } 77 : 78 : // Previous block is available 79 0 : const auto& last_block = previous_blocks.back(); 80 0 : bit_field.MarkAsCompressed(CompressedHeaderBitField::Flag::PREV_BLOCK_HASH); 81 : 82 : // Compute compressed time diff 83 0 : const int64_t time_diff = nTime - last_block.nTime; 84 0 : if (time_diff <= std::numeric_limits<int16_t>::max() && time_diff >= std::numeric_limits<int16_t>::min()) { 85 0 : time_offset = static_cast<int16_t>(time_diff); 86 0 : bit_field.MarkAsCompressed(CompressedHeaderBitField::Flag::TIMESTAMP); 87 0 : } 88 : 89 : // If n_bits matches previous block, it can be compressed (not sent at all) 90 0 : if (nBits == last_block.nBits) { 91 0 : bit_field.MarkAsCompressed(CompressedHeaderBitField::Flag::NBITS); 92 0 : } 93 0 : } 94 : 95 0 : void CompressibleBlockHeader::Uncompress(const std::vector<CBlockHeader>& previous_blocks, std::list<int32_t>& last_unique_versions) 96 : { 97 0 : if (previous_blocks.empty()) { 98 : // First block in chain is always uncompressed 99 0 : SaveVersionAsMostRecent(last_unique_versions, nVersion); 100 0 : return; 101 : } 102 : 103 : // We have the previous block 104 0 : const auto& last_block = previous_blocks.back(); 105 : 106 : // Uncompress version 107 0 : if (bit_field.IsVersionCompressed()) { 108 0 : const auto version_offset = bit_field.GetVersionOffset(); 109 0 : if (version_offset <= last_unique_versions.size()) { 110 0 : auto version_it = last_unique_versions.begin(); 111 0 : std::advance(version_it, version_offset - 1); 112 0 : nVersion = *version_it; 113 0 : MarkVersionAsMostRecent(last_unique_versions, version_it); 114 0 : } 115 0 : } else { 116 : // Save the version as the most recent one 117 0 : SaveVersionAsMostRecent(last_unique_versions, nVersion); 118 : } 119 : 120 : // Uncompress prev block hash 121 0 : if (bit_field.IsCompressed(CompressedHeaderBitField::Flag::PREV_BLOCK_HASH)) { 122 0 : hashPrevBlock = last_block.GetHash(); 123 0 : } 124 : 125 : // Uncompress timestamp 126 0 : if (bit_field.IsCompressed(CompressedHeaderBitField::Flag::TIMESTAMP)) { 127 0 : nTime = last_block.nTime + time_offset; 128 0 : } 129 : 130 : // Uncompress n_bits 131 0 : if (bit_field.IsCompressed(CompressedHeaderBitField::Flag::NBITS)) { 132 0 : nBits = last_block.nBits; 133 0 : } 134 0 : }