mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-15 11:36:00 -05:00
172 lines
6.4 KiB
C
172 lines
6.4 KiB
C
![]() |
// Copyright (c) The Bitcoin Core developers
|
||
|
// Distributed under the MIT software license, see the accompanying
|
||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||
|
|
||
|
#ifndef BITCOIN_CLUSTER_LINEARIZE_H
|
||
|
#define BITCOIN_CLUSTER_LINEARIZE_H
|
||
|
|
||
|
#include <stdint.h>
|
||
|
#include <vector>
|
||
|
#include <utility>
|
||
|
|
||
|
#include <util/feefrac.h>
|
||
|
|
||
|
namespace cluster_linearize {
|
||
|
|
||
|
/** Data type to represent cluster input.
|
||
|
*
|
||
|
* cluster[i].first is tx_i's fee and size.
|
||
|
* cluster[i].second[j] is true iff tx_i spends one or more of tx_j's outputs.
|
||
|
*/
|
||
|
template<typename SetType>
|
||
|
using Cluster = std::vector<std::pair<FeeFrac, SetType>>;
|
||
|
|
||
|
/** Data type to represent transaction indices in clusters. */
|
||
|
using ClusterIndex = uint32_t;
|
||
|
|
||
|
/** Data structure that holds a transaction graph's preprocessed data (fee, size, ancestors,
|
||
|
* descendants). */
|
||
|
template<typename SetType>
|
||
|
class DepGraph
|
||
|
{
|
||
|
/** Information about a single transaction. */
|
||
|
struct Entry
|
||
|
{
|
||
|
/** Fee and size of transaction itself. */
|
||
|
FeeFrac feerate;
|
||
|
/** All ancestors of the transaction (including itself). */
|
||
|
SetType ancestors;
|
||
|
/** All descendants of the transaction (including itself). */
|
||
|
SetType descendants;
|
||
|
|
||
|
/** Equality operator (primarily for for testing purposes). */
|
||
|
friend bool operator==(const Entry&, const Entry&) noexcept = default;
|
||
|
|
||
|
/** Construct an empty entry. */
|
||
|
Entry() noexcept = default;
|
||
|
/** Construct an entry with a given feerate, ancestor set, descendant set. */
|
||
|
Entry(const FeeFrac& f, const SetType& a, const SetType& d) noexcept : feerate(f), ancestors(a), descendants(d) {}
|
||
|
};
|
||
|
|
||
|
/** Data for each transaction, in the same order as the Cluster it was constructed from. */
|
||
|
std::vector<Entry> entries;
|
||
|
|
||
|
public:
|
||
|
/** Equality operator (primarily for testing purposes). */
|
||
|
friend bool operator==(const DepGraph&, const DepGraph&) noexcept = default;
|
||
|
|
||
|
// Default constructors.
|
||
|
DepGraph() noexcept = default;
|
||
|
DepGraph(const DepGraph&) noexcept = default;
|
||
|
DepGraph(DepGraph&&) noexcept = default;
|
||
|
DepGraph& operator=(const DepGraph&) noexcept = default;
|
||
|
DepGraph& operator=(DepGraph&&) noexcept = default;
|
||
|
|
||
|
/** Construct a DepGraph object for ntx transactions, with no dependencies.
|
||
|
*
|
||
|
* Complexity: O(N) where N=ntx.
|
||
|
**/
|
||
|
explicit DepGraph(ClusterIndex ntx) noexcept
|
||
|
{
|
||
|
Assume(ntx <= SetType::Size());
|
||
|
entries.resize(ntx);
|
||
|
for (ClusterIndex i = 0; i < ntx; ++i) {
|
||
|
entries[i].ancestors = SetType::Singleton(i);
|
||
|
entries[i].descendants = SetType::Singleton(i);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** Construct a DepGraph object given a cluster.
|
||
|
*
|
||
|
* Complexity: O(N^2) where N=cluster.size().
|
||
|
*/
|
||
|
explicit DepGraph(const Cluster<SetType>& cluster) noexcept : entries(cluster.size())
|
||
|
{
|
||
|
for (ClusterIndex i = 0; i < cluster.size(); ++i) {
|
||
|
// Fill in fee and size.
|
||
|
entries[i].feerate = cluster[i].first;
|
||
|
// Fill in direct parents as ancestors.
|
||
|
entries[i].ancestors = cluster[i].second;
|
||
|
// Make sure transactions are ancestors of themselves.
|
||
|
entries[i].ancestors.Set(i);
|
||
|
}
|
||
|
|
||
|
// Propagate ancestor information.
|
||
|
for (ClusterIndex i = 0; i < entries.size(); ++i) {
|
||
|
// At this point, entries[a].ancestors[b] is true iff b is an ancestor of a and there
|
||
|
// is a path from a to b through the subgraph consisting of {a, b} union
|
||
|
// {0, 1, ..., (i-1)}.
|
||
|
SetType to_merge = entries[i].ancestors;
|
||
|
for (ClusterIndex j = 0; j < entries.size(); ++j) {
|
||
|
if (entries[j].ancestors[i]) {
|
||
|
entries[j].ancestors |= to_merge;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Fill in descendant information by transposing the ancestor information.
|
||
|
for (ClusterIndex i = 0; i < entries.size(); ++i) {
|
||
|
for (auto j : entries[i].ancestors) {
|
||
|
entries[j].descendants.Set(i);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** Get the number of transactions in the graph. Complexity: O(1). */
|
||
|
auto TxCount() const noexcept { return entries.size(); }
|
||
|
/** Get the feerate of a given transaction i. Complexity: O(1). */
|
||
|
const FeeFrac& FeeRate(ClusterIndex i) const noexcept { return entries[i].feerate; }
|
||
|
/** Get the ancestors of a given transaction i. Complexity: O(1). */
|
||
|
const SetType& Ancestors(ClusterIndex i) const noexcept { return entries[i].ancestors; }
|
||
|
/** Get the descendants of a given transaction i. Complexity: O(1). */
|
||
|
const SetType& Descendants(ClusterIndex i) const noexcept { return entries[i].descendants; }
|
||
|
|
||
|
/** Add a new unconnected transaction to this transaction graph (at the end), and return its
|
||
|
* ClusterIndex.
|
||
|
*
|
||
|
* Complexity: O(1) (amortized, due to resizing of backing vector).
|
||
|
*/
|
||
|
ClusterIndex AddTransaction(const FeeFrac& feefrac) noexcept
|
||
|
{
|
||
|
Assume(TxCount() < SetType::Size());
|
||
|
ClusterIndex new_idx = TxCount();
|
||
|
entries.emplace_back(feefrac, SetType::Singleton(new_idx), SetType::Singleton(new_idx));
|
||
|
return new_idx;
|
||
|
}
|
||
|
|
||
|
/** Modify this transaction graph, adding a dependency between a specified parent and child.
|
||
|
*
|
||
|
* Complexity: O(N) where N=TxCount().
|
||
|
**/
|
||
|
void AddDependency(ClusterIndex parent, ClusterIndex child) noexcept
|
||
|
{
|
||
|
// Bail out if dependency is already implied.
|
||
|
if (entries[child].ancestors[parent]) return;
|
||
|
// To each ancestor of the parent, add as descendants the descendants of the child.
|
||
|
const auto& chl_des = entries[child].descendants;
|
||
|
for (auto anc_of_par : Ancestors(parent)) {
|
||
|
entries[anc_of_par].descendants |= chl_des;
|
||
|
}
|
||
|
// To each descendant of the child, add as ancestors the ancestors of the parent.
|
||
|
const auto& par_anc = entries[parent].ancestors;
|
||
|
for (auto dec_of_chl : Descendants(child)) {
|
||
|
entries[dec_of_chl].ancestors |= par_anc;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** Compute the aggregate feerate of a set of nodes in this graph.
|
||
|
*
|
||
|
* Complexity: O(N) where N=elems.Count().
|
||
|
**/
|
||
|
FeeFrac FeeRate(const SetType& elems) const noexcept
|
||
|
{
|
||
|
FeeFrac ret;
|
||
|
for (auto pos : elems) ret += entries[pos].feerate;
|
||
|
return ret;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
} // namespace cluster_linearize
|
||
|
|
||
|
#endif // BITCOIN_CLUSTER_LINEARIZE_H
|