mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-04-29 14:59:39 -04:00
txgraph: Add GetChunkFeerate function (feature)
This adds a function to query the chunk feerate of a transaction, by caching it inside the Entry objects.
This commit is contained in:
parent
c80aecc24d
commit
1d27b74c8e
3 changed files with 71 additions and 2 deletions
|
@ -321,6 +321,19 @@ FUZZ_TARGET(txgraph)
|
|||
assert(feerate == sim.graph.FeeRate(simpos));
|
||||
}
|
||||
break;
|
||||
} else if (command-- == 0) {
|
||||
// GetChunkFeerate.
|
||||
auto ref = pick_fn();
|
||||
auto feerate = real->GetChunkFeerate(*ref);
|
||||
auto simpos = sim.Find(ref);
|
||||
if (simpos == SimTxGraph::MISSING) {
|
||||
assert(feerate.IsEmpty());
|
||||
} else {
|
||||
// Just do some quick checks that the reported value is in range. A full
|
||||
// recomputation of expected chunk feerates is done at the end.
|
||||
assert(feerate.size >= sim.graph.FeeRate(simpos).size);
|
||||
}
|
||||
break;
|
||||
} else if (command-- == 0) {
|
||||
// GetAncestors/GetDescendants.
|
||||
auto ref = pick_fn();
|
||||
|
@ -405,13 +418,21 @@ FUZZ_TARGET(txgraph)
|
|||
simlin.push_back(simpos);
|
||||
}
|
||||
// Construct a chunking object for the simulated graph, using the reported cluster
|
||||
// linearization as ordering.
|
||||
// linearization as ordering, and compare it against the reported chunk feerates.
|
||||
cluster_linearize::LinearizationChunking simlinchunk(sim.graph, simlin);
|
||||
DepGraphIndex idx{0};
|
||||
for (unsigned chunknum = 0; chunknum < simlinchunk.NumChunksLeft(); ++chunknum) {
|
||||
auto chunk = simlinchunk.GetChunk(chunknum);
|
||||
// Require that the chunks of cluster linearizations are connected (this must
|
||||
// be the case as all linearizations inside are PostLinearized).
|
||||
assert(sim.graph.IsConnected(chunk.transactions));
|
||||
// Check the chunk feerates of all transactions in the cluster.
|
||||
while (chunk.transactions.Any()) {
|
||||
assert(chunk.transactions[simlin[idx]]);
|
||||
chunk.transactions.Reset(simlin[idx]);
|
||||
assert(chunk.feerate == real->GetChunkFeerate(*cluster[idx]));
|
||||
++idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -221,6 +221,8 @@ private:
|
|||
Ref* m_ref{nullptr};
|
||||
/** Which Cluster and position therein this Entry appears in. */
|
||||
Locator m_locator;
|
||||
/** The chunk feerate of this transaction (if not missing). */
|
||||
FeePerWeight m_chunk_feerate;
|
||||
};
|
||||
|
||||
/** The set of all transactions. GraphIndex values index into this. */
|
||||
|
@ -301,6 +303,7 @@ public:
|
|||
void SetTransactionFee(const Ref&, int64_t fee) noexcept final;
|
||||
|
||||
bool Exists(const Ref& arg) noexcept final;
|
||||
FeePerWeight GetChunkFeerate(const Ref& arg) noexcept final;
|
||||
FeePerWeight GetIndividualFeerate(const Ref& arg) noexcept final;
|
||||
std::vector<Ref*> GetCluster(const Ref& arg) noexcept final;
|
||||
std::vector<Ref*> GetAncestors(const Ref& arg) noexcept final;
|
||||
|
@ -317,6 +320,24 @@ void Cluster::Updated(TxGraphImpl& graph) noexcept
|
|||
auto& entry = graph.m_entries[m_mapping[idx]];
|
||||
entry.m_locator.SetPresent(this, idx);
|
||||
}
|
||||
|
||||
// Compute its chunking and store its information in the Entry's m_chunk_feerate.
|
||||
LinearizationChunking chunking(m_depgraph, m_linearization);
|
||||
LinearizationIndex lin_idx{0};
|
||||
// Iterate over the chunks.
|
||||
for (unsigned chunk_idx = 0; chunk_idx < chunking.NumChunksLeft(); ++chunk_idx) {
|
||||
auto chunk = chunking.GetChunk(chunk_idx);
|
||||
Assume(chunk.transactions.Any());
|
||||
// Iterate over the transactions in the linearization, which must match those in chunk.
|
||||
do {
|
||||
DepGraphIndex idx = m_linearization[lin_idx++];
|
||||
GraphIndex graph_idx = m_mapping[idx];
|
||||
auto& entry = graph.m_entries[graph_idx];
|
||||
entry.m_chunk_feerate = FeePerWeight::FromFeeFrac(chunk.feerate);
|
||||
Assume(chunk.transactions[idx]);
|
||||
chunk.transactions.Reset(idx);
|
||||
} while(chunk.transactions.Any());
|
||||
}
|
||||
}
|
||||
|
||||
void Cluster::ApplyRemovals(TxGraphImpl& graph, std::span<GraphIndex>& to_remove) noexcept
|
||||
|
@ -1108,6 +1129,23 @@ FeePerWeight TxGraphImpl::GetIndividualFeerate(const Ref& arg) noexcept
|
|||
return cluster->GetIndividualFeerate(m_entries[GetRefIndex(arg)].m_locator.index);
|
||||
}
|
||||
|
||||
FeePerWeight TxGraphImpl::GetChunkFeerate(const Ref& arg) noexcept
|
||||
{
|
||||
// Return the empty FeePerWeight if the passed Ref is empty.
|
||||
if (GetRefGraph(arg) == nullptr) return {};
|
||||
Assume(GetRefGraph(arg) == this);
|
||||
// Apply all removals and dependencies, as the result might be inaccurate otherwise.
|
||||
ApplyDependencies();
|
||||
// Find the cluster the argument is in, and return the empty FeePerWeight if it isn't in any.
|
||||
auto cluster = m_entries[GetRefIndex(arg)].m_locator.cluster;
|
||||
if (cluster == nullptr) return {};
|
||||
// Make sure the Cluster has an acceptable quality level, and then return the transaction's
|
||||
// chunk feerate.
|
||||
MakeAcceptable(*cluster);
|
||||
const auto& entry = m_entries[GetRefIndex(arg)];
|
||||
return entry.m_chunk_feerate;
|
||||
}
|
||||
|
||||
void Cluster::SetFee(TxGraphImpl& graph, DepGraphIndex idx, int64_t fee) noexcept
|
||||
{
|
||||
// Make sure the specified DepGraphIndex exists in this Cluster.
|
||||
|
@ -1159,10 +1197,11 @@ void Cluster::SanityCheck(const TxGraphImpl& graph) const
|
|||
// Check that the Entry has a locator pointing back to this Cluster & position within it.
|
||||
assert(entry.m_locator.cluster == this);
|
||||
assert(entry.m_locator.index == lin_pos);
|
||||
// Check linearization position.
|
||||
// Check linearization position and chunk feerate.
|
||||
if (!linchunking.GetChunk(0).transactions[lin_pos]) {
|
||||
linchunking.MarkDone(linchunking.GetChunk(0).transactions);
|
||||
}
|
||||
assert(entry.m_chunk_feerate == linchunking.GetChunk(0).feerate);
|
||||
// If this Cluster has an acceptable quality level, its chunks must be connected.
|
||||
if (IsAcceptable()) {
|
||||
assert(m_depgraph.IsConnected(linchunking.GetChunk(0).transactions));
|
||||
|
|
|
@ -29,6 +29,12 @@ static constexpr unsigned CLUSTER_COUNT_LIMIT{64};
|
|||
*
|
||||
* For more explanation, see https://delvingbitcoin.org/t/introduction-to-cluster-linearization/1032
|
||||
*
|
||||
* This linearization is partitioned into chunks: groups of transactions that according to this
|
||||
* order would be mined together. Each chunk consists of the highest-feerate prefix of what remains
|
||||
* of the linearization after removing previous chunks. TxGraph guarantees that the maintained
|
||||
* linearization always results in chunks consisting of transactions that are connected. A chunk's
|
||||
* transactions always belong to the same cluster.
|
||||
*
|
||||
* The interface is designed to accommodate an implementation that only stores the transitive
|
||||
* closure of dependencies, so if B spends C, it does not distinguish between "A spending B" and
|
||||
* "A spending both B and C".
|
||||
|
@ -82,6 +88,9 @@ public:
|
|||
/** Get the individual transaction feerate of transaction arg. Returns the empty FeePerWeight
|
||||
* if arg does not exist. */
|
||||
virtual FeePerWeight GetIndividualFeerate(const Ref& arg) noexcept = 0;
|
||||
/** Get the feerate of the chunk which transaction arg is in. Returns the empty FeePerWeight if
|
||||
* arg does not exist. */
|
||||
virtual FeePerWeight GetChunkFeerate(const Ref& arg) noexcept = 0;
|
||||
/** Get pointers to all transactions in the cluster which arg is in. The transactions will be
|
||||
* returned in graph order. Returns {} if arg does not exist in the graph. */
|
||||
virtual std::vector<Ref*> GetCluster(const Ref& arg) noexcept = 0;
|
||||
|
|
Loading…
Add table
Reference in a new issue