Bitcoin Core 31.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 cluster_linearize {
21
23
98{
100 static uint64_t SignedToUnsigned(int64_t x) noexcept
101 {
102 if (x < 0) {
103 return 2 * uint64_t(-(x + 1)) + 1;
104 } else {
105 return 2 * uint64_t(x);
106 }
107 }
108
110 static int64_t UnsignedToSigned(uint64_t x) noexcept
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) {
139 DepGraphIndex idx = topo_order[topo_idx];
140 // Write size, which must be larger than 0.
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;
147 for (DepGraphIndex dep_dist = 0; dep_dist < topo_idx; ++dep_dist) {
149 DepGraphIndex dep_idx = topo_order[topo_idx - 1 - dep_dist];
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;
157 written_parents.Set(dep_idx);
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>
185 void Unser(Stream& s, DepGraph<SetType>& depgraph)
186 {
189 DepGraph<SetType> topo_depgraph;
192 std::vector<DepGraphIndex> reordering;
194 DepGraphIndex total_size{0};
195
196 // Read transactions in topological order.
197 while (true) {
198 FeeFrac new_feerate;
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).
210 uint64_t coded_fee;
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);
214 new_feerate = {UnsignedToSigned(coded_fee), size};
215 // Read dependency information.
216 auto topo_idx = reordering.size();
217 s >> VARINT(diff);
218 for (DepGraphIndex dep_dist = 0; dep_dist < topo_idx; ++dep_dist) {
220 DepGraphIndex dep_topo_idx = topo_idx - 1 - dep_dist;
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.
225 new_ancestors |= topo_depgraph.Ancestors(dep_topo_idx);
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.
253 total_size = diff;
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.
278 depgraph = DepGraph(topo_depgraph, reordering, total_size);
279 }
280};
281
283template<typename SetType>
284void SanityCheck(const DepGraph<SetType>& depgraph)
285{
286 // Verify Positions and PositionRange consistency.
287 DepGraphIndex num_positions{0};
288 DepGraphIndex position_range{0};
289 for (DepGraphIndex i : depgraph.Positions()) {
290 ++num_positions;
291 position_range = i + 1;
292 }
293 assert(num_positions == depgraph.TxCount());
294 assert(position_range == depgraph.PositionRange());
295 assert(position_range >= num_positions);
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;
329 VectorWriter writer(ser, 0);
330 writer << Using<DepGraphFormatter>(depgraph);
331 SpanReader reader(ser);
332 DepGraph<SetType> decoded_depgraph;
333 reader >> Using<DepGraphFormatter>(decoded_depgraph);
334 assert(depgraph == decoded_depgraph);
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();
340 reader = SpanReader{ser};
341 decoded_depgraph = {};
342 reader >> Using<DepGraphFormatter>(decoded_depgraph);
343 assert(depgraph == 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
395inline uint64_t MaxOptimalLinearizationCost(DepGraphIndex cluster_count)
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,...
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.
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
SocketId Stream
Definition: util.h:30
#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:22
int64_t fee
Definition: feefrac.h:89
int32_t size
Definition: feefrac.h:90
bool IsEmpty() const noexcept
Check if this is empty (size and fee are 0).
Definition: feefrac.h:102
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)
assert(!tx.IsCoinBase())