Bitcoin Core 嵌入式 ASMap 数据:IP 前缀到 ASN 映射的数据来源、协作流程与构建集成
本文以 嵌入式 ASMap 数据说明文档 为核心,系统讲解 Bitcoin Core 中 -asmap 功能背后的 ASMap 数据是如何采集、交叉验证、编码并嵌入发行版二进制的:包括 RPKI/IRR/Routeviews 三类数据源的优先级机制、多人协作的确定性构建与签名流程、asmap-tool.py 编码工具链,以及数据从 src/node/data/ip_asn.dat 经 CMake 编译定义到 NetGroupManager 分桶的完整源码链路。读完后,你可以复现 ASMap 文件的编码与校验步骤,并理解发行版更新内嵌 ASMap 数据的具体操作方式。
背景:为什么需要按 ASN 分桶
ASMap 功能(通过 -asmap 选项启用)允许 Bitcoin Core 在 netgroup 分桶时,使用对等节点自治系统的 ASN(Autonomous System Number,可理解为 ISP/主机商标识),而不是默认的 IP 前缀分桶。默认行为下,分桶依据 IP 前缀划分,但这无法防止一个大型主机商主导连接集合——因为这类公司通常控制着大量互不连续的 IP 段,其不同 IP 段会散落在不同的 IP 前缀桶中。改用 ASN 分桶后,一个节点就不会连接到同一个 AS 下的多个节点,从而提升对等节点集合的多样性。
从源码注释可以进一步确认这一动机:src/netgroup.h 中对 NetGroupManager 的注释明确写道,按 AS 分桶是为了让节点连接到多样化的对等方集合,"This is done in response to Erebus attack, but also to generally diversify the connections every node creates, especially useful when a large fraction of nodes operate under a couple of cloud providers"(这是对 Erebus 攻击的回应,也是在大量节点集中于少数云服务商时的普遍性多样化手段)。
启用 ASMap 的前提是拥有"IP 前缀 → ASN"的映射数据。该数据可以通过外部文件提供,但为了在用户无法自行提供文件时仍可用该功能,Bitcoin Core 还在构建中嵌入了一份默认的映射数据。这就是本文档的主体内容。
数据源与 Kartograf 工具
ASMap 本质上是 IP 前缀到 ASN 的映射,即某一刻互联网路由表的快照。这份文档指出了数据面临的固有难题:
- 路由表的部分内容波动性极高,且 BGP 协议本身存在已知漏洞,因此采集数据并证明其一致性非常困难;
- 仅从单一可信来源获取数据同样成问题(单点信任风险)。
为尽可能化解这些不确定性,社区创建了 Kartograf 工具(asmap/kartograf 项目)。Kartograf 的映射数据来自三类来源,且优先级明确:
- RPKI 与 IRR:这两者本身就是用于防御 BGP 安全问题的安全机制,因此被认为更安全,其数据优先采用;
- Routeviews:一个可信的 BGP 流量收集者,仅用于 RPKI 和 IRR 未覆盖的 IP 地址空间。
Kartograf 解析、处理并合并这些数据源的过程是确定性的:给定这些不同来源的原始下载文件,任何人都可以自行构建映射文件,并验证其结果与其他用户一致。而在地图文件被 Bitcoin Core 使用之前,还需要一步编码——这一步使用 contrib/asmap 中的 asmap-tool.py 完成,该步骤同样具有确定性。
多人协作的确定性采集与签名流程
即使处理过程是确定性的,获取初始输入数据时的高波动性依然是挑战:如果用户不想信任 ASMap 文件的单一制作者,怎么办?文档给出的答案是多方同时采集、多数结果共识:
- 多个用户可以在完全相同的时刻启动下载过程,这样他们下载到的数据大概率足够相似,最终会产出相同的输出文件;
- 这一过程由 asmap-data 项目(
asmap/asmap-data仓库)定期组织协作; - 若某个结果哈希被至少 5 位参与者签名确认,则对应的 ASMap 文件会被合入该仓库供公开使用;
- 合入还要求至少另外 2 位审查者确认上述流程被正确执行、且编码步骤产出的文件哈希一致;
- 新文件会持续地创建,但没有中央计划或固定时间表。
这个"确定性流程 + 多方独立执行 + 签名与审查"的组合,使得嵌入式 ASMap 数据在不依赖单点信任的前提下具备可验证性。
编码工具链:asmap-tool.py
contrib/asmap/README.md 说明,ASMap 文本文件体积较大,需编码为二进制格式后才能与 -asmap 配合使用。asmap-tool.py 提供四类操作:
python3 asmap-tool.py encode /path/to/input.file /path/to/output.file
python3 asmap-tool.py decode /path/to/input.file /path/to/output.file
python3 asmap-tool.py diff /path/to/first.file /path/to/path/to/second.file
python3 asmap-tool.py diff_addrs /path/to/first.file /path/to/second.file addrs.file
(以上命令按 README 原样整理,diff 一条的第二个参数应为 /path/to/second.file。)各命令要点:
- encode:将文本 ASMap 编码为二进制。
--fill/-f标志可通过"若相邻网段已有 ASN 分配,则对未映射网段推断分配"进一步压缩输出;但该过程是有损的(丢失哪些网段原本未分配的信息),且仅当输入 ASMap 足够完整、目标是省空间且不打算日后做 diff 时才建议使用; - decode:反向解码;
--fill同样会重分配子网以减小体积,--non-overlapping/-n则输出严格不重叠的网段范围; - diff:比较两个 ASMap 文件,输出网段 ASN 分配状态的变化,包括三种状态:重新分配到新 AS(
AS26496 # was AS20738)、仅存在于第一个文件(# 220.157.65.0/24 was AS9723)、仅存在于第二个文件(# was unassigned);支持--ignore-unassigned/-i忽略新增网段; - diff_addrs:结合两个 ASMap 与本机已知节点列表(由
bitcoin-cli getnodeaddresses导出),只报告本机实际对等方 IP 所经历的 AS 变化,例如:
bitcoin-cli getnodeaddresses 0 > addrs.json
python3 asmap-tool.py diff_addrs path/to/first.file path/to/second.file addrs.json
README 还提示:数据量较大时上述命令可能需要几分钟,建议用 pypy3 加速。
源码链路:嵌入数据如何进入二进制
嵌入过程由构建系统完成。CMakeLists.txt 定义了开关:
option(WITH_EMBEDDED_ASMAP "Embed default ASMap data." ON)
默认开启;仅当启用 BUILD_FOR_FUZZING 时会被强制关闭(见 CMakeLists.txt 附近的 set(WITH_EMBEDDED_ASMAP OFF),该分支同时关闭了钱包、GUI 等目标)。
开启后,src/CMakeLists.txt 中:
if(WITH_EMBEDDED_ASMAP)
target_compile_definitions(bitcoin_node PRIVATE ENABLE_EMBEDDED_ASMAP=1)
include(TargetDataSources)
target_raw_data_sources(bitcoin_node NAMESPACE node::data
node/data/ip_asn.dat
)
endif()
即:向 bitcoin_node 目标注入 ENABLE_EMBEDDED_ASMAP=1 编译定义,并把 src/node/data/ip_asn.dat 这份原始数据以 node::data 命名空间生成头文件形式内联进二进制。ip_asn.dat 正是文档"Release process"一节要求替换的那个文件——它位于 src/node/data/ 下。
运行时加载:外部文件与内嵌数据的选择逻辑
启动阶段的加载逻辑在 src/init.cpp 中。-asmap 参数的定义(src/init.cpp)说明了两种用法:
-asmap=<file>:指定用于节点分桶的 ASN 映射文件;相对路径会被加上"按网络区分的 datadir 前缀";- 若参数为布尔值(
-asmap或-asmap=1):使用二进制中内嵌的映射数据。
加载流程为:参数被设置且未取反时,先判断是否给了具体文件路径——给了则解析路径、检查文件存在(不存在则 Could not find asmap file),调用 DecodeAsmap 读取(解析失败则 Could not parse asmap file),并构建 NetGroupManager::WithLoadedAsmap;未给路径时则走内嵌分支,直接引用编译期生成的 node::data::ip_asn 字节数组,先用 CheckStandardAsmap 做标准数据校验(128 位 IPv6 空间),失败会报 Could not read embedded asmap data,数据不存在则报 Embedded asmap data not available(对应 WITH_EMBEDDED_ASMAP 关闭的构建)。最后,无论哪条路径都会记录 asmap 版本:
LogInfo("Using asmap version %s for IP bucketing", asmap_version.ToString());
这里的 asmap 版本由 src/util/asmap.h 中的 AsmapVersion 计算,是一个标识当前所用映射数据的校验和。同一头文件还声明了 Interpret(从 asmap 字节与 IP 解出 ASN)、SanityCheckAsmap(按位宽做健全性检查)和 DecodeAsmap(读取并校验二进制文件)。
而 NetGroupManager(src/netgroup.h)对外提供三个工厂:WithEmbeddedAsmap、WithLoadedAsmap、NoAsmap;核心接口包括 GetGroup(返回地址的分组标识,保证不会向同一 netgroup 的地址发起两条连接)、GetMappedAS(返回到达该地址 BGP 路径上的 AS)、以及 ASMapHealthCheck(分析并记录基于 ASMap 的桶的健康度)。头文件注释还说明:asmap 以 const 方式在构造时初始化,因而线程安全;m_asmap 可以指向运行时加载的 m_loaded_asmap,也可以指向嵌入数据。
发行版更新流程(Release Process)
文档最后一节给出了嵌入式 ASMap 数据在版本发布时的更新规程:
- 临近新版本发布时,应当用 asmap-data 仓库中更新的 ASMap 文件替换
ip_asn.dat(当前仓库中该文件位于 src/node/data/ip_asn.dat),使新数据被嵌入发行版; - 优先选择现成的近期文件:理想情况下应已存在最近构建的文件可直接选用;
- 必要时发起新一轮构建:若没有合适文件,可按前文描述的协作流程启动一次新的创建过程,以获取用于该版本的新鲜地图。
由于 Kartograf 处理与 asmap-tool.py 编码都是确定性的,且合入 asmap-data 仓库需要多方签名与审查,因此替换 ip_asn.dat 这一动作本身的风险是受控的——开发者只需确认所选文件的哈希与 asmap-data 仓库中已验证的文件一致。
验证与测试支撑
仓库中围绕 asmap 的验证手段与上述文档流程相互印证:
- 单元测试数据 src/test/data/asmap.raw(见 src/test/CMakeLists.txt),用于 src/test/netbase_tests.cpp 等测试;
- Fuzz 目标 src/test/fuzz/asmap.cpp 与 src/test/fuzz/asmap_direct.cpp 针对解码与解读路径做模糊测试;
- 性能基准 src/bench/asmap.cpp 同样仅在
WITH_EMBEDDED_ASMAP开启时编入(src/bench/CMakeLists.txt),说明嵌入数据也支撑着分桶性能的基准测量。
小结
doc/asmap-data.md 描述的是一条"数据可信度"链路:RPKI/IRR 优先 + Routeviews 兜底的采集、Kartograf 确定性处理、多方同时下载与 5 签 2 审的共识机制、asmap-tool.py 确定性编码,最终落到 src/node/data/ip_asn.dat 并由 WITH_EMBEDDED_ASMAP(默认 ON)嵌入发行版;运行期则通过 -asmap 参数在"外部文件"与"内嵌数据"之间切换,并以 AsmapVersion 校验和对外标识当前使用的映射。对运维者而言,日常只需关注 -asmap 的使用与 diff_addrs 对现有对等方影响面的评估;对版本发布者而言,则按 Release process 一节在发布前更新内嵌文件即可。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0622
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00