Bitcoin Core 31.0.0
P2P Digital Currency
Loading...
Searching...
No Matches
cluster_linearize.h
Go to the documentation of this file.
1// Copyright (c) The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#ifndef BITCOIN_TEST_UTIL_CLUSTER_LINEARIZE_H
6#define BITCOIN_TEST_UTIL_CLUSTER_LINEARIZE_H
7
8#include <cluster_linearize.h>
9#include <serialize.h>
10#include <span.h>
11#include <streams.h>
12#include <util/bitset.h>
13#include <util/feefrac.h>
14
15#include <cstdint>
16#include <numeric>
17#include <utility>
18#include <vector>
19
20namespace {
21
22using namespace cluster_linearize;
23
25
99struct DepGraphFormatter
100{
102 [[maybe_unused]] static uint64_t SignedToUnsigned(int64_t x) noexcept
103 {
104 if (x < 0) {
105 return 2 * uint64_t(-(x + 1)) + 1;
106 } else {
107 return 2 * uint64_t(x);
108 }
109 }
110
112 [[maybe_unused]] static int64_t UnsignedToSigned(uint64_t x) noexcept
113 {
114 if (x & 1) {
115 return -int64_t(x / 2) - 1;
116 } else {
117 return int64_t(x / 2);
118 }
119 }
120
121 template <typename Stream, typename SetType>
122 static void Ser(Stream& s, const DepGraph<SetType>& depgraph)
123 {
125 std::vector<DepGraphIndex> topo_order;
126 topo_order.reserve(depgraph.TxCount());
127 for (auto i : depgraph.Positions()) topo_order.push_back(i);
128 std::sort(topo_order.begin(), topo_order.end(), [&](DepGraphIndex a, DepGraphIndex b) {
129 auto anc_a = depgraph.Ancestors(a).Count(), anc_b = depgraph.Ancestors(b).Count();
130 if (anc_a != anc_b) return anc_a < anc_b;
131 return a < b;
132 });
133
136 SetType done;
137
138 // Loop over the transactions in topological order.
139 for (DepGraphIndex topo_idx = 0; topo_idx < topo_order.size(); ++topo_idx) {
142 // Write size, which must be larger than 0.
144 // Write fee, encoded as an unsigned varint (odd=negative, even=non-negative).
145 s << VARINT(SignedToUnsigned(depgraph.FeeRate(idx).fee));
146 // Write dependency information.
147 SetType written_parents;
148 uint64_t diff = 0;
152 // Ignore transactions which are already known to be ancestors.
153 if (depgraph.Descendants(dep_idx).Overlaps(written_parents)) continue;
154 if (depgraph.Ancestors(idx)[dep_idx]) {
155 // When an actual parent is encountered, encode how many non-parents were skipped
156 // before it.
157 s << VARINT(diff);
158 diff = 0;
160 } else {
161 // When a non-parent is encountered, increment the skip counter.
162 ++diff;
163 }
164 }
165 // Write position information.
166 auto add_holes = SetType::Fill(idx) - done - depgraph.Positions();
167 if (add_holes.None()) {
168 // The new transaction is to be inserted N positions back from the end of the
169 // cluster. Emit N to indicate that that many insertion choices are skipped.
170 auto skips = (done - SetType::Fill(idx)).Count();
171 s << VARINT(diff + skips);
172 } else {
173 // The new transaction is to be appended at the end of the cluster, after N holes.
174 // Emit current_cluster_size + N, to indicate all insertion choices are skipped,
175 // plus N possibilities for the number of holes.
176 s << VARINT(diff + done.Count() + add_holes.Count());
177 done |= add_holes;
178 }
179 done.Set(idx);
180 }
181
182 // Output a final 0 to denote the end of the graph.
183 s << uint8_t{0};
184 }
185
186 template <typename Stream, typename SetType>
187 void Unser(Stream& s, DepGraph<SetType>& depgraph)
188 {
194 std::vector<DepGraphIndex> reordering;
197
198 // Read transactions in topological order.
199 while (true) {
201 SetType new_ancestors;
202 uint64_t diff{0};
203 bool read_error{false};
204 try {
205 // Read size. Size 0 signifies the end of the DepGraph.
206 int32_t size;
208 size &= 0x3FFFFF; // Enough for size up to 4M.
209 static_assert(0x3FFFFF >= 4000000);
210 if (size == 0 || topo_depgraph.TxCount() == SetType::Size()) break;
211 // Read fee, encoded as an unsigned varint (odd=negative, even=non-negative).
213 s >> VARINT(coded_fee);
214 coded_fee &= 0xFFFFFFFFFFFFF; // Enough for fee between -21M...21M BTC.
215 static_assert(0xFFFFFFFFFFFFF > uint64_t{2} * 21000000 * 100000000);
217 // Read dependency information.
218 auto topo_idx = reordering.size();
219 s >> VARINT(diff);
223 // Ignore transactions which are already known ancestors of topo_idx.
224 if (new_ancestors[dep_topo_idx]) continue;
225 if (diff == 0) {
226 // When the skip counter has reached 0, add an actual dependency.
228 // And read the number of skips after it.
229 s >> VARINT(diff);
230 } else {
231 // Otherwise, dep_topo_idx is not a parent. Decrement and continue.
232 --diff;
233 }
234 }
235 } catch (const std::ios_base::failure&) {
236 // Continue even if a read error was encountered.
237 read_error = true;
238 }
239 // Construct a new transaction whenever we made it past the new_feerate construction.
240 if (new_feerate.IsEmpty()) break;
241 assert(reordering.size() < SetType::Size());
242 auto topo_idx = topo_depgraph.AddTransaction(new_feerate);
243 topo_depgraph.AddDependencies(new_ancestors, topo_idx);
244 if (total_size < SetType::Size()) {
245 // Normal case.
246 diff %= SetType::Size();
247 if (diff <= total_size) {
248 // Insert the new transaction at distance diff back from the end.
249 for (auto& pos : reordering) {
250 pos += (pos >= total_size - diff);
251 }
252 reordering.push_back(total_size++ - diff);
253 } else {
254 // Append diff - total_size holes at the end, plus the new transaction.
256 reordering.push_back(total_size++);
257 }
258 } else {
259 // In case total_size == SetType::Size, it is not possible to insert the new
260 // transaction without exceeding SetType's size. Instead, interpret diff as an
261 // index into the holes, and overwrite a position there. This branch is never used
262 // when deserializing the output of the serializer, but gives meaning to otherwise
263 // invalid input.
264 diff %= (SetType::Size() - reordering.size());
265 SetType holes = SetType::Fill(SetType::Size());
266 for (auto pos : reordering) holes.Reset(pos);
267 for (auto pos : holes) {
268 if (diff == 0) {
269 reordering.push_back(pos);
270 break;
271 }
272 --diff;
273 }
274 }
275 // Stop if a read error was encountered during deserialization.
276 if (read_error) break;
277 }
278
279 // Construct the original cluster order depgraph.
281 }
282};
283
285template<typename SetType>
286void SanityCheck(const DepGraph<SetType>& depgraph)
287{
288 // Verify Positions and PositionRange consistency.
291 for (DepGraphIndex i : depgraph.Positions()) {
293 position_range = i + 1;
294 }
295 assert(num_positions == depgraph.TxCount());
296 assert(position_range == depgraph.PositionRange());
298 assert(position_range <= SetType::Size());
299 // Consistency check between ancestors internally.
300 for (DepGraphIndex i : depgraph.Positions()) {
301 // Transactions include themselves as ancestors.
302 assert(depgraph.Ancestors(i)[i]);
303 // If a is an ancestor of b, then b's ancestors must include all of a's ancestors.
304 for (auto a : depgraph.Ancestors(i)) {
305 assert(depgraph.Ancestors(i).IsSupersetOf(depgraph.Ancestors(a)));
306 }
307 }
308 // Consistency check between ancestors and descendants.
309 for (DepGraphIndex i : depgraph.Positions()) {
310 for (DepGraphIndex j : depgraph.Positions()) {
311 assert(depgraph.Ancestors(i)[j] == depgraph.Descendants(j)[i]);
312 }
313 // No transaction is a parent or child of itself.
314 auto parents = depgraph.GetReducedParents(i);
315 auto children = depgraph.GetReducedChildren(i);
316 assert(!parents[i]);
317 assert(!children[i]);
318 // Parents of a transaction do not have ancestors inside those parents (except itself).
319 // Note that even the transaction itself may be missing (if it is part of a cycle).
320 for (auto parent : parents) {
321 assert((depgraph.Ancestors(parent) & parents).IsSubsetOf(SetType::Singleton(parent)));
322 }
323 // Similar for children and descendants.
324 for (auto child : children) {
325 assert((depgraph.Descendants(child) & children).IsSubsetOf(SetType::Singleton(child)));
326 }
327 }
328 if (depgraph.IsAcyclic()) {
329 // If DepGraph is acyclic, serialize + deserialize must roundtrip.
330 std::vector<unsigned char> ser;
337 assert(reader.empty());
338 // It must also deserialize correctly without the terminal 0 byte (as the deserializer
339 // will upon EOF still return what it read so far).
340 assert(ser.size() >= 1 && ser.back() == 0);
341 ser.pop_back();
343 decoded_depgraph = {};
346 assert(reader.empty());
347
348 // In acyclic graphs, the union of parents with parents of parents etc. yields the
349 // full ancestor set (and similar for children and descendants).
350 std::vector<SetType> parents(depgraph.PositionRange()), children(depgraph.PositionRange());
351 for (DepGraphIndex i : depgraph.Positions()) {
352 parents[i] = depgraph.GetReducedParents(i);
353 children[i] = depgraph.GetReducedChildren(i);
354 }
355 for (auto i : depgraph.Positions()) {
356 // Initialize the set of ancestors with just the current transaction itself.
357 SetType ancestors = SetType::Singleton(i);
358 // Iteratively add parents of all transactions in the ancestor set to itself.
359 while (true) {
360 const auto old_ancestors = ancestors;
361 for (auto j : ancestors) ancestors |= parents[j];
362 // Stop when no more changes are being made.
363 if (old_ancestors == ancestors) break;
364 }
365 assert(ancestors == depgraph.Ancestors(i));
366
367 // Initialize the set of descendants with just the current transaction itself.
368 SetType descendants = SetType::Singleton(i);
369 // Iteratively add children of all transactions in the descendant set to itself.
370 while (true) {
371 const auto old_descendants = descendants;
372 for (auto j : descendants) descendants |= children[j];
373 // Stop when no more changes are being made.
374 if (old_descendants == descendants) break;
375 }
376 assert(descendants == depgraph.Descendants(i));
377 }
378 }
379}
380
382template<typename SetType>
383void SanityCheck(const DepGraph<SetType>& depgraph, std::span<const DepGraphIndex> linearization)
384{
385 // Check completeness.
386 assert(linearization.size() == depgraph.TxCount());
387 SetType done;
388 for (auto i : linearization) {
389 // Check transaction position is in range.
390 assert(depgraph.Positions()[i]);
391 // Check topology and lack of duplicates.
392 assert((depgraph.Ancestors(i) - done) == SetType::Singleton(i));
393 done.Set(i);
394 }
395}
396
398{
399 // These are the largest numbers seen returned as cost by Linearize(), in a large randomized
400 // trial. There exist almost certainly far worse cases, but they are unlikely to be
401 // encountered in randomized tests. The purpose of these numbers is guaranteeing that for
402 // *some* reasonable cost bound, optimal linearizations are always found.
403 static constexpr uint64_t COSTS[65] = {
404 0,
405 0, 545, 928, 1633, 2647, 4065, 5598, 8258,
406 9505, 11471, 14137, 19553, 20460, 26191, 28397, 32599,
407 41631, 47419, 56329, 57767, 72196, 63652, 95366, 96537,
408 115653, 125407, 131734, 145090, 156349, 164665, 194224, 203953,
409 207710, 225878, 239971, 252284, 256534, 222142, 251332, 357098,
410 325788, 295867, 410053, 497483, 533892, 576572, 577845, 572400,
411 592536, 455082, 609249, 659130, 714091, 544507, 718788, 562378,
412 601926, 1025081, 732725, 708896, 738224, 900445, 1092519, 1139946
413 };
414 assert(cluster_count < std::size(COSTS));
415 // Multiply the table number by two, to account for the fact that they are not absolutes.
416 return COSTS[cluster_count] * 2;
417}
418
419} // namespace
420
421#endif // BITCOIN_TEST_UTIL_CLUSTER_LINEARIZE_H
std::conditional_t<(BITS<=32), bitset_detail::IntBitSet< uint32_t >, std::conditional_t<(BITS<=std::numeric_limits< size_t >::digits), bitset_detail::IntBitSet< size_t >, bitset_detail::MultiIntBitSet< size_t,(BITS+std::numeric_limits< size_t >::digits - 1)/std::numeric_limits< size_t >::digits > > > BitSet
Definition bitset.h:523
Minimal stream for reading from an existing byte array by std::span.
Definition streams.h:83
Data structure that holds a transaction graph's preprocessed data (fee, size, ancestors,...
uint32_t DepGraphIndex
Data type to represent transaction indices in DepGraphs and the clusters they represent.
#define VARINT(obj)
Definition serialize.h:491
#define VARINT_MODE(obj, mode)
Definition serialize.h:490
@ NONNEGATIVE_SIGNED
Data structure storing a fee and size, ordered by increasing fee/size.
Definition feefrac.h:40
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.
Definition time.h:73
assert(!tx.IsCoinBase())