Skip to content

Commit eaab55f

Browse files
committed
clusterlin: rework DepGraphFormatter::Unser
This commit does not change the serialization format. Its purpose is making a few changes already in order to reduce the diff size of the later commit that introduces support for holes in DepGraph. The previous approach was to immediately construct a transaction as soon as its feerate was known in a preliminary position, and then undo that, and place it in the correct position once the position information is known (such that a deserialization error in between would not result in an inconsistent state). The new approach is to delay the actual transaction creation until all its information is known, avoiding the need to undo and redo. This requires a different means of determining whether dependencies are redundant, but that has the advantage that a later commit can apply all dependencies at once, reducing the complexity of deserialization.
1 parent 5901cf7 commit eaab55f

File tree

1 file changed

+30
-22
lines changed

1 file changed

+30
-22
lines changed

src/test/util/cluster_linearize.h

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -189,10 +189,17 @@ struct DepGraphFormatter
189189
/** Mapping from serialization order to cluster order, used later to reconstruct the
190190
* cluster order. */
191191
std::vector<ClusterIndex> reordering;
192+
/** How big the entries vector in the reconstructed depgraph will be (before the
193+
* introduction of holes in a further commit, this always equals reordering.size()). */
194+
ClusterIndex total_size{0};
192195

193196
// Read transactions in topological order.
194-
try {
195-
while (true) {
197+
while (true) {
198+
FeeFrac new_feerate; //!< The new transaction's fee and size.
199+
SetType new_ancestors; //!< The new transaction's ancestors (excluding itself).
200+
uint64_t diff{0}; //!< How many potential parents/insertions we have to skip.
201+
bool read_error{false};
202+
try {
196203
// Read size. Size 0 signifies the end of the DepGraph.
197204
int32_t size;
198205
s >> VARINT_MODE(size, VarIntMode::NONNEGATIVE_SIGNED);
@@ -204,42 +211,43 @@ struct DepGraphFormatter
204211
s >> VARINT(coded_fee);
205212
coded_fee &= 0xFFFFFFFFFFFFF; // Enough for fee between -21M...21M BTC.
206213
static_assert(0xFFFFFFFFFFFFF > uint64_t{2} * 21000000 * 100000000);
207-
auto fee = UnsignedToSigned(coded_fee);
208-
// Extend topo_depgraph with the new transaction (preliminarily at the end).
209-
auto topo_idx = topo_depgraph.AddTransaction({fee, size});
210-
reordering.push_back(reordering.size());
214+
new_feerate = {UnsignedToSigned(coded_fee), size};
211215
// Read dependency information.
212-
uint64_t diff = 0; //!< How many potential parents we have to skip.
216+
auto topo_idx = reordering.size();
213217
s >> VARINT(diff);
214218
for (ClusterIndex dep_dist = 0; dep_dist < topo_idx; ++dep_dist) {
215219
/** Which topo_depgraph index we are currently considering as parent of topo_idx. */
216220
ClusterIndex dep_topo_idx = topo_idx - 1 - dep_dist;
217221
// Ignore transactions which are already known ancestors of topo_idx.
218-
if (topo_depgraph.Descendants(dep_topo_idx)[topo_idx]) continue;
222+
if (new_ancestors[dep_topo_idx]) continue;
219223
if (diff == 0) {
220224
// When the skip counter has reached 0, add an actual dependency.
221-
topo_depgraph.AddDependency(dep_topo_idx, topo_idx);
225+
new_ancestors |= topo_depgraph.Ancestors(dep_topo_idx);
222226
// And read the number of skips after it.
223227
s >> VARINT(diff);
224228
} else {
225229
// Otherwise, dep_topo_idx is not a parent. Decrement and continue.
226230
--diff;
227231
}
228232
}
229-
// If we reach this point, we can interpret the remaining skip value as how far
230-
// from the end of reordering the new transaction should be placed (wrapping
231-
// around), so remove the preliminary position it was put in above (which was to
232-
// make sure that if a deserialization exception occurs, the new transaction still
233-
// has some entry in reordering).
234-
reordering.pop_back();
235-
ClusterIndex insert_distance = diff % (reordering.size() + 1);
236-
// And then update reordering to reflect this new transaction's insertion.
237-
for (auto& pos : reordering) {
238-
pos += (pos >= reordering.size() - insert_distance);
239-
}
240-
reordering.push_back(reordering.size() - insert_distance);
233+
} catch (const std::ios_base::failure&) {
234+
// Continue even if a read error was encountered.
235+
read_error = true;
241236
}
242-
} catch (const std::ios_base::failure&) {}
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+
for (auto parent : new_ancestors) topo_depgraph.AddDependency(parent, topo_idx);
242+
diff %= total_size + 1;
243+
// Insert the new transaction at distance diff back from the end.
244+
for (auto& pos : reordering) {
245+
pos += (pos >= total_size - diff);
246+
}
247+
reordering.push_back(total_size++ - diff);
248+
// Stop if a read error was encountered during deserialization.
249+
if (read_error) break;
250+
}
243251

244252
// Construct the original cluster order depgraph.
245253
depgraph = DepGraph(topo_depgraph, reordering);

0 commit comments

Comments
 (0)