Bitcoin Core 29.99.0
P2P Digital Currency
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
24using TestBitSet = BitSet<32>;
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) {
141 DepGraphIndex idx = topo_order[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;
149 for (DepGraphIndex dep_dist = 0; dep_dist < topo_idx; ++dep_dist) {
151 DepGraphIndex dep_idx = topo_order[topo_idx - 1 - dep_dist];
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;
159 written_parents.Set(dep_idx);
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 {
191 DepGraph<SetType> topo_depgraph;
194 std::vector<DepGraphIndex> reordering;
196 DepGraphIndex total_size{0};
197
198 // Read transactions in topological order.
199 while (true) {
200 FeeFrac new_feerate;
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).
212 uint64_t coded_fee;
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);
216 new_feerate = {UnsignedToSigned(coded_fee), size};
217 // Read dependency information.
218 auto topo_idx = reordering.size();
219 s >> VARINT(diff);
220 for (DepGraphIndex dep_dist = 0; dep_dist < topo_idx; ++dep_dist) {
222 DepGraphIndex dep_topo_idx = topo_idx - 1 - dep_dist;
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.
227 new_ancestors |= topo_depgraph.Ancestors(dep_topo_idx);
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.
255 total_size = diff;
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.
280 depgraph = DepGraph(topo_depgraph, reordering, total_size);
281 }
282};
283
285template<typename SetType>
286void SanityCheck(const DepGraph<SetType>& depgraph)
287{
288 // Verify Positions and PositionRange consistency.
289 DepGraphIndex num_positions{0};
290 DepGraphIndex position_range{0};
291 for (DepGraphIndex i : depgraph.Positions()) {
292 ++num_positions;
293 position_range = i + 1;
294 }
295 assert(num_positions == depgraph.TxCount());
296 assert(position_range == depgraph.PositionRange());
297 assert(position_range >= num_positions);
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;
331 VectorWriter writer(ser, 0);
332 writer << Using<DepGraphFormatter>(depgraph);
333 SpanReader reader(ser);
334 DepGraph<TestBitSet> decoded_depgraph;
335 reader >> Using<DepGraphFormatter>(decoded_depgraph);
336 assert(depgraph == decoded_depgraph);
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();
342 reader = SpanReader{ser};
343 decoded_depgraph = {};
344 reader >> Using<DepGraphFormatter>(decoded_depgraph);
345 assert(depgraph == 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 TestBitSet 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) == TestBitSet::Singleton(i));
393 done.Set(i);
394 }
395}
396
397inline uint64_t MaxOptimalLinearizationIters(DepGraphIndex cluster_count)
398{
399 // We assume sqrt(2^k)+1 candidate-finding iterations per candidate to be found, plus ceil(k/4)
400 // startup cost when up to k unlinearization transactions remain, plus ceil(n^2/64) overall
401 // startup cost in Linearize. Thus, we can compute the upper bound for a whole linearization
402 // (summing for k=1..n) using the Python expression:
403 //
404 // [sum((k+3)//4 + math.isqrt(2**k) + 1 for k in range(1, n + 1)) + (n**2 + 63) // 64 for n in range(0, 65)]
405 //
406 // Note that these are just assumptions, as the proven upper bound grows with 2^k, not
407 // sqrt(2^k).
408 static constexpr uint64_t MAX_OPTIMAL_ITERS[65] = {
409 0, 4, 8, 12, 18, 26, 37, 51, 70, 97, 133, 182, 251, 346, 480, 666, 927, 1296, 1815, 2545,
410 3576, 5031, 7087, 9991, 14094, 19895, 28096, 39690, 56083, 79263, 112041, 158391, 223936,
411 316629, 447712, 633086, 895241, 1265980, 1790280, 2531747, 3580335, 5063259, 7160424,
412 10126257, 14320575, 20252230, 28640853, 40504150, 57281380, 81007962, 114562410, 162015557,
413 229124437, 324030718, 458248463, 648061011, 916496483, 1296121563, 1832992493, 2592242635,
414 3665984477, 5184484745, 7331968412, 10368968930, 14663936244
415 };
416 assert(cluster_count < sizeof(MAX_OPTIMAL_ITERS) / sizeof(MAX_OPTIMAL_ITERS[0]));
417 return MAX_OPTIMAL_ITERS[cluster_count];
418}
419
420} // namespace
421
422#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:525
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,...
const SetType & Ancestors(DepGraphIndex i) const noexcept
Get the ancestors of a given transaction i.
SetType GetReducedChildren(DepGraphIndex i) const noexcept
Compute the (reduced) set of children of node i in this graph.
SetType GetReducedParents(DepGraphIndex i) const noexcept
Compute the (reduced) set of parents of node i in this graph.
const FeeFrac & FeeRate(DepGraphIndex i) const noexcept
Get the feerate of a given transaction i.
DepGraphIndex PositionRange() const noexcept
Get the range of positions in this DepGraph.
DepGraphIndex AddTransaction(const FeeFrac &feefrac) noexcept
Add a new unconnected transaction to this transaction graph (in the first available position),...
auto TxCount() const noexcept
Get the number of transactions in the graph.
const SetType & Descendants(DepGraphIndex i) const noexcept
Get the descendants of a given transaction i.
const SetType & Positions() const noexcept
Get the set of transactions positions in use.
void AddDependencies(const SetType &parents, DepGraphIndex child) noexcept
Modify this transaction graph, adding multiple parents to a specified child.
bool IsAcyclic() const noexcept
Check if this graph is acyclic.
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
int64_t fee
Definition: feefrac.h:107
int32_t size
Definition: feefrac.h:108
bool IsEmpty() const noexcept
Check if this is empty (size and fee are 0).
Definition: feefrac.h:120
assert(!tx.IsCoinBase())