ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Bitcoin Core 集群内存池设计详解:线性化、费用率图表与 RBF 的源码级解析

Bitcoin Core 集群内存池设计详解:线性化、费用率图表与 RBF 的源码级解析 Bitcoin Core 集群内存池设计详解线性化、费用率图表与 RBF 的源码级解析【免费下载链接】bitcoinBitcoin Core integration/staging tree项目地址: https://gitcode.com/GitHub_Trending/bi/bitcoin本文以 Bitcoin Core 的 mempool-design.md 设计文档为核心完整讲清算法侧的集群内存池cluster mempool体系如何把内存池事务建模为有向图、如何用线性化 块chunk组织出最优出块顺序、如何用费用率图表feerate diagram统一驱动挖矿、淘汰与 RBF 替换判定。读完后你将理解 v31.0 起 Bitcoin Core 内存池策略的数学基础并能对应到TxGraph、cluster_linearize等源码模块中的具体实现。1. 内存池的事务图模型从 parent/child 到 cluster设计文档首先给出的核心抽象是把内存池中所有未确认交易视为一张有向图directed graph。若交易 B 花费spend了交易 A 创建的输出即存在一条从 B 指向 A 的边——此时 B 是 A 的子交易childA 是 B 的父交易parent。在此之上文档定义了递归扩展概念祖先ancestors递归地包含其父交易、父交易的父交易……即所有直接或间接为其出资确认前提的交易后代descendants递归地包含其子交易、子交易的子交易……集群cluster图的连通分量即集合中任意两个交易都可沿边双向互达。某个交易的集群由该交易、其祖先与后代、以及这些交易的祖先与后代递推构成——因此集群里不仅包含父子还包含祖孙、兄弟、远房表亲等一切相关交易。这一抽象在源码中直接落地为TxGraph类src/txgraph.h。其头文件注释明确写道图内的连通分量称为 clusterwhenever one transaction is reachable from another, through any sequence of is-parent-of or is-child-of relations, they belong to the same cluster与文档定义一一对应。接口层提供了GetCluster()、GetAncestors()、GetDescendants()等函数src/txgraph.h#L139-L158并且设计上刻意兼容只存储依赖传递闭包的实现——即若 B 花费 C它不区分A 花费 B和A 同时花费 B 与 C。底层数据结构DepGraphsrc/cluster_linearize.h印证了这一点每个事务的 Entry 只保存三样东西——单个费用率、全部祖先集合、全部后代集合用位集生产实现为BitSet64见 src/txgraph.cpp#L110表示。直接父子关系并不显式存储而是通过GetReducedParents()/GetReducedChildren()从祖先/后代集合中推断出来src/cluster_linearize.h#L211-L243。需要提醒的是文档中所有size相关量都是策略术语vsize 指经 sigops 调整后的虚拟大小BIP 141 大小与 sigop 大小的最大值详见同目录的 mempool-terminology.md。2. 线性化与 chunk为整个集群构造最优出块顺序文档的第二个核心概念是线性化linearization。每个集群cluster被排序成一个拓扑有效的顺序topologically valid order即任何交易都不会出现在其祖先之前。目标是构造这样的线性化费用率最高的子集排在最前其次是剩余交易中费用率次高的子集依此类推。文档把这类子集称为chunk块并指出一个关键性质一个线性化中的 chunks 总是按单调递减的费用率排列。这一算法在源码中是SpanningForestStateSFLspanning-forest linearization实现于 src/cluster_linearize.h。其工作过程可以概括为初始所有依赖边均为非激活状态每个交易自成一块反复在依赖边上激活/去激活即合并/拆分 chunk直到状态达到topological且optimal——optimal 的判据是不存在一条激活依赖其顶部 chunk 费用率严格高于底部 chunk 费用率。文档注释中给出了定理式结论whenever the state is optimal, the produced linearization will also be optimal (in the convexified feerate diagram sense)即状态最优可证明输出线性化在凸化费用率图表意义下最优若仍有预算进一步把等费用率的 chunk 拆分为最小成分minimal state最终按费用率从高到低输出各 chunkchunk 内部按拓扑序排列。整个过程受成本模型约束SFLDefaultCostModelsrc/cluster_linearize.h#L476-L545为每个操作建立了基于 2026 年 2 月多机基准测试拟合的整数成本表达式每个成本单位约合 0.52.5 纳秒对应TxGraph构造参数中的acceptable_cost——决定每个集群最多投入多少优化算力best effort only, not a strong guarantee见 src/txgraph.h#L20-L46 的类注释。chunk 的计算本身非常简洁见ChunkLinearization()src/cluster_linearize.h#L446-L464沿线性化逐个处理交易只要新交易与已吸收部分的合并费用率仍高于上一个 chunk就把它吸收进来从而保证 chunk 费用率序列严格单调递减。文档还指出跨集群的合并方式给定两个或多个已线性化的集群把各自按费用率排好的 chunks 做归并排序merge sort即得到并集上线性化。这与TxGraph::GetMainStagingDiagrams()注释中the combined respective feerate diagrams, including chunks from all clusterssrc/txgraph.h#L169-L173的语义一致——全内存池的线性化天然由所有集群的 chunks 归并而成。3. 费用率图表比较两个线性化的统一标尺文档定义了费用率图表feerate diagram以累计大小cumulative size为横轴、累计费用cumulative fee为纵轴沿 chunk 逐块推进绘制出的折线图。它是比较两个线性化优劣的统一工具文档给出三种比较结论不可比incomparable两者互不包含——存在某些尺寸点 A 的累计费用更高也存在其他尺寸点 B 更高等价equivalent在所有尺寸点上累计费用完全相同严格更优strictly better可比且至少存在一个尺寸点其中一方累计费用严格更高。这个比较在实现上就是CompareChunks()基于FeeFrac精确的分数型费用率表示src/util/feefrac.h实现避免浮点误差干扰策略判定。测试 src/test/rbf_tests.cpp#L489-L497 显式验证了三种结论std::is_lt、std::is_gt与std::partial_ordering::unordered对应不可比。文档最后给出的理论注脚值得保留这一目标本质上是**最大比率闭包问题maximal-ratio closure problem**的一个实例与露天矿开采open pit mining领域的最大权闭包问题密切相关——这也解释了 SFL 算法中top/bottom顶部/底部术语的由来。4. 挖矿与淘汰线性化同一张表的头尾两端文档Mining/eviction一节说明了线性化的两大用途区块构建mining构造区块模板时从线性化前端依次选取 chunks内存池淘汰eviction需要为内存池腾出空间时从线性化后端逐块淘汰。即同一份按费用率降序的 chunks 序列头端喂给出块尾端喂给淘汰两者互为镜像。源码中这两个方向各有一个入口出块端TxGraph::GetBlockBuilder()返回一个BlockBuilder迭代器通过GetCurrentChunk()取当前建议纳入的 chunk 及其费用率Include()/Skip()前进src/txgraph.h#L180-L201。注意Skip()的语义Further chunks from the same cluster as the current one will not be reported anymore——跳过某 chunk 后同集群的后续 chunk 不再报告保证拓扑一致性。矿工侧调用点在 src/node/miner.cpp#L302 的GetBlockBuilderChunk()。淘汰端GetWorstMainChunk()返回主图中最后一个 chunk 及其费用率src/txgraph.h#L202-L206且特意以逆拓扑序返回每个交易排在所有其后代之前保证直接删除这批交易不会留下悬挂的依赖链。5. Replace-by-fee用费用率图表取代简单费用规则文档的 RBF 一节指出了一个历史缺陷在集群内存池实现之前替换replacement判定存在两类错误——即使替换会让内存池对矿工更有利也可能被拒绝反之新交易比被替换交易更不受矿工欢迎时替换却可能被放行。集群内存池带来了更严格的判据比较替换前后整个内存池的费用率图表仅当替换使图表严格更优strictly better时才接受。文档给出直观解释简单情形下替换交易的费用率和费用都应当高于被替换交易但当某些交易存在未确认父交易时不存在一个可以简单描述的必须支付多少费用才能成功替换一组交易的公式唯一的判据就是结果内存池的费用率图表在某个尺寸点变好且在任何尺寸点都不变差。源码中这条路径清晰可查ImprovesFeerateDiagram()src/policy/rbf.cpp#L127-L140对变更集changeset计算替换前后两个 chunk 序列再用CompareChunks()断言新图表std::is_gt旧图表否则拒绝并返回 insufficient feerate: does not improve feerate diagram该比较依赖TxGraph的staging 图机制StartStaging()建立一份主图的工作副本在副本上施加替换后调用GetMainStagingDiagrams()取回两份图表且自动剔除两边完全相同的集群因为不影响比较结果判定失败则AbortStaging()丢弃、成功则CommitStaging()src/txgraph.h#L109-L120此外仍有传统 BIP 125 规则并行生效替换交易必须支付不低于原交易的费用且新增费用必须按增量中继费incremental relay feerate覆盖其自身带宽PaysForRBF()src/policy/rbf.cpp#L100-L125以及影响范围上限MAX_REPLACEMENT_CANDIDATES{100}个独立集群src/policy/rbf.h#L24-L26。完整的 RBF 替换规则文档见 mempool-replacements.md。6. 内存池限制为什么必须约束集群规模文档Mempool limits一节给出了两方面的动机两者共同指向限制集群从而限制 chunk的最大规模接近最优的区块构建需要小 chunk。按费用率降序选取 chunk 构建区块模板时只有当任意 chunk 的最大尺寸远小于区块大小贪心选取才接近最优。若单个 chunk 过大可能因装不下而浪费区块空间避免淘汰的级联效应。内存池淘汰时不希望因为一笔可能很小的新交易越过尺寸上限就一次性驱逐大量无关交易——限制集群规模能兜住这种尾部风险计算复杂度约束。对某交易做线性化所需的计算量随集群内交易数多项式增长只有限制集群交易数才能保证在合理时间内找到良好理想情况下最优的线性化。由此得出的硬性规则是文档给出的最重要可验证事实之一提交到内存池的交易不得使任何集群超过集群上限每集群最多 64 笔交易、总计最多 101 kvB。这两个数字在源码中有多处一致定义可以逐一核验常数值定义位置DEFAULT_CLUSTER_LIMIT64默认集群交易数上限src/policy/policy.h#L72DEFAULT_CLUSTER_SIZE_LIMIT_KVB101默认集群大小上限kvBsrc/policy/policy.h#L74MAX_CLUSTER_COUNT_LIMIT64允许的硬上限BitSet位集尺寸也由此决定src/txgraph.h#L18mempool_limits结构cluster_count{DEFAULT_CLUSTER_LIMIT}、cluster_size_vbytes{DEFAULT_CLUSTER_SIZE_LIMIT_KVB * 1000}src/kernel/mempool_limits.h#L20-L22运行节点上可以用getmempoolinfoRPC 观察当前生效的limitclustersizesrc/rpc/mempool.cpp#L1093。调试参数-limitclustercountn允许调小计数上限默认 64最大 64DEBUG_ONLY 类别在 src/init.cpp#L690 注册、在 src/node/mempool_args.cpp#L110-L111 校验不得超过MAX_CLUSTER_COUNT_LIMIT——注意该上限是硬性的不能通过参数放大超过 64因为TxGraph的位集实现以 64 为容量。当超限发生时TxGraph会进入oversized状态多数查询接口对 oversized 图不可用但所有 mutator 始终可用且Trim()会按快速尽力策略移除交易含其后代直到恢复满足集群限制src/txgraph.h#L122-L178。7. 相关背景与延伸阅读文档末尾的 References/Notes 给出了两条线索一是该实现自v31.0起随 cluster mempool 方案PR#33629合入二是费用率图表在挖矿、淘汰与替换判定三处的统一使用原理。在仓库内理解本文时可沿以下路径继续深入src/txgraph.h 与 src/txgraph.cpp内存池事务图的完整接口与实现包括 main/staging 双层图、chunk 划分保证与BlockBuildersrc/cluster_linearize.hSFL 线性化算法全文含大段算法性质证明式注释以及DepGraph传递闭包结构src/txmempool.h / src/txmempool.cpp内存池主体如何持有m_txgraph并把它接入选入、淘汰与 RBF 流程src/test/cluster_linearize_tests.cpp、src/test/txgraph_tests.cpp、src/test/rbf_tests.cpp线性化最优性、TxGraph 行为与图表比较的单元测试src/test/fuzz/txgraph.cpp 用随机模拟图对TxGraph全部接口做等价性 fuzzsrc/bench/txgraph.cppTxGraph 基准测试可观察线性化在 64 交易、100000 vB 集群规模下的实际开销mempool-terminology.md 与 packages.md费用/大小术语约定以及 package 提交如何与集群限制共存例如static_assert(DEFAULT_CLUSTER_LIMIT MAX_PACKAGE_COUNT)保证单个 package 永远不会撑爆集群见 src/policy/packages.h#L29。8. 小结集群内存池设计把内存池该怎么排从一堆启发式规则收敛为一张统一的数学对象——按费用率单调递减分块、跨集群归并的全局线性化。它同时回答了三个问题矿工从头部拿 chunk 出块、节点从尾部丢 chunk 淘汰、RBF 用前后两张费用率图表的严格优劣比较决定替换成败。而64 笔 / 101 kvB的集群限制则是让整个体系在时间复杂度与出块质量上都可控的工程护栏。这套机制自 v31.0 起成为 Bitcoin Core 内存池策略的骨架理解它即理解当前版本交易中继、出块与替换行为的第一性原理。【免费下载链接】bitcoinBitcoin Core integration/staging tree项目地址: https://gitcode.com/GitHub_Trending/bi/bitcoin创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表