MCPcopy Create free account
hub / github.com/bitcoin/bitcoin / InitData

Method InitData

src/blockencodings.cpp:59–179  ·  view source on GitHub ↗

Reconstructing a compact block is in the hot-path for block relay, * so we want to do it as quickly as possible. Because this often * involves iterating over the entire mempool, we put all the data we * need (ie the wtxid and a reference to the actual transaction data) * in a vector and iterate over the vector directly. This allows optimal * CPU caching behaviour, at a cost of only 40 bytes p

Source from the content-addressed store, hash-verified

57 * CPU caching behaviour, at a cost of only 40 bytes per transaction.
58 */
59ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& cmpctblock, const std::vector<std::pair<Wtxid, CTransactionRef>>& extra_txn)
60{
61 LogDebug(BCLog::CMPCTBLOCK, "Initializing PartiallyDownloadedBlock for block %s using a cmpctblock of %u bytes\n", cmpctblock.header.GetHash().ToString(), GetSerializeSize(cmpctblock));
62 if (cmpctblock.header.IsNull() || (cmpctblock.shorttxids.empty() && cmpctblock.prefilledtxn.empty()))
63 return READ_STATUS_INVALID;
64 if (cmpctblock.shorttxids.size() + cmpctblock.prefilledtxn.size() > MAX_BLOCK_WEIGHT / MIN_SERIALIZABLE_TRANSACTION_WEIGHT)
65 return READ_STATUS_INVALID;
66
67 if (!header.IsNull() || !txn_available.empty()) return READ_STATUS_INVALID;
68
69 header = cmpctblock.header;
70 txn_available.resize(cmpctblock.BlockTxCount());
71
72 int32_t lastprefilledindex = -1;
73 for (size_t i = 0; i < cmpctblock.prefilledtxn.size(); i++) {
74 if (cmpctblock.prefilledtxn[i].tx->IsNull())
75 return READ_STATUS_INVALID;
76
77 lastprefilledindex += cmpctblock.prefilledtxn[i].index + 1; //index is a uint16_t, so can't overflow here
78 if (lastprefilledindex > std::numeric_limits<uint16_t>::max())
79 return READ_STATUS_INVALID;
80 if ((uint32_t)lastprefilledindex > cmpctblock.shorttxids.size() + i) {
81 // If we are inserting a tx at an index greater than our full list of shorttxids
82 // plus the number of prefilled txn we've inserted, then we have txn for which we
83 // have neither a prefilled txn or a shorttxid!
84 return READ_STATUS_INVALID;
85 }
86 txn_available[lastprefilledindex] = cmpctblock.prefilledtxn[i].tx;
87 }
88 prefilled_count = cmpctblock.prefilledtxn.size();
89
90 // Calculate map of txids -> positions and check mempool to see what we have (or don't)
91 // Because well-formed cmpctblock messages will have a (relatively) uniform distribution
92 // of short IDs, any highly-uneven distribution of elements can be safely treated as a
93 // READ_STATUS_FAILED.
94 std::unordered_map<uint64_t, uint16_t> shorttxids(cmpctblock.shorttxids.size());
95 uint16_t index_offset = 0;
96 for (size_t i = 0; i < cmpctblock.shorttxids.size(); i++) {
97 while (txn_available[i + index_offset])
98 index_offset++;
99 shorttxids[cmpctblock.shorttxids[i]] = i + index_offset;
100 // To determine the chance that the number of entries in a bucket exceeds N,
101 // we use the fact that the number of elements in a single bucket is
102 // binomially distributed (with n = the number of shorttxids S, and p =
103 // 1 / the number of buckets), that in the worst case the number of buckets is
104 // equal to S (due to std::unordered_map having a default load factor of 1.0),
105 // and that the chance for any bucket to exceed N elements is at most
106 // buckets * (the chance that any given bucket is above N elements).
107 // Thus: P(max_elements_per_bucket > N) <= S * (1 - cdf(binomial(n=S,p=1/S), N)).
108 // If we assume blocks of up to 16000, allowing 12 elements per bucket should
109 // only fail once per ~1 million block transfers (per peer and connection).
110 if (shorttxids.bucket_size(shorttxids.bucket(cmpctblock.shorttxids[i])) > 12)
111 return READ_STATUS_FAILED;
112 }
113 if (shorttxids.size() != cmpctblock.shorttxids.size())
114 return READ_STATUS_FAILED; // Short ID collision
115
116 std::vector<bool> have_txn(txn_available.size());

Callers 4

ProcessMessageMethod · 0.80
BOOST_AUTO_TEST_CASEFunction · 0.80
BlockEncodingBenchFunction · 0.80

Calls 13

GetSerializeSizeFunction · 0.85
BlockTxCountMethod · 0.80
findMethod · 0.80
GetSharedTxMethod · 0.80
ToStringMethod · 0.45
GetHashMethod · 0.45
IsNullMethod · 0.45
emptyMethod · 0.45
sizeMethod · 0.45
resizeMethod · 0.45
GetShortIDMethod · 0.45
endMethod · 0.45

Tested by 1

BOOST_AUTO_TEST_CASEFunction · 0.64