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