用真实 channel.db 验证 LND 支付数据 KV 到 SQL 迁移:migration1 外部数据库测试指南

发布时间:2026/9/27 9:54:30
用真实 channel.db 验证 LND 支付数据 KV 到 SQL 迁移:migration1 外部数据库测试指南 区块链【免费下载链接】lndLightning Network Daemon ⚡️项目地址https://gitcode.com/gh_mirrors/ln/lnd点击查看免费下载本文是 LNDLightning Network Daemon项目中payments/db/migration1迁移模块的实战调试指南聚焦如何使用migration_external_test.go测试将你手上真实的channel.dbbbolt或channel.sqlite文件作为迁移源在本地把支付数据从 KV 存储完整搬到 SQL 数据库并做逐字段深校验。读完本文你将掌握外部测试数据的放置位置、测试代码的两处必改点、Postgres/SQLite 三种后端对应的构建标签组合以及迁移背后按序流式迁移、批处理深比较、历史支付修复等底层原理可直接用于复现或排查你节点上的支付迁移问题。背景为什么需要一个“外部数据”迁移测试LND 的通道状态与支付数据历史上存储在 bboltchannel.db中属于 KV 结构而新的 SQL 后端SQLite / Postgres把支付数据拆分为 payments、payment_htlc_attempts、route_hops、payment_duplicates 等多张规范化表。payments/db/migration1目录下的代码负责把旧 KV 支付存储整体迁移到 SQL 存储核心入口是MigratePaymentsKVToSQL见 sql_migration.go并且这个迁移被注册进 LND 主流程作为 SQL 数据库 schema 迁移的一环在 config_builder.go 中调用。问题在于常规单元测试用的是程序构造的 KV 数据见 sql_migration_test.go无法覆盖真实节点数据库里各种历史遗留形态——比如旧版本产生的重复支付duplicate payments、attempt ID 为 0 的遗留 HTLC、被遮蔽路由的孤立总额等。因此仓库提供了 testdata/README.md 所描述的“外部数据库测试”专门让开发者把真实的channel.db或channel.sqlite拷进来做迁移验证定位迁移 bug。这个测试目录当前只有 README 而没有任何数据库文件因为生产数据绝不应提交进仓库文件需由使用者本地自行准备。前置准备三套迁移源与对应构建标签TestMigrationWithExternalDB定义于 migration_external_test.go支持三种 KV 数据源均以只读方式打开bbolt 后端显式设置ReadOnly: true见同文件 connectBBolt迁移源文件/参数目标 SQL 后端所需构建标签bboltchannel.db拷贝到payments/db/migration1/testdata/设fileName channel.dbPostgrestest_db_postgresSQLitechannel.sqlite拷贝到payments/db/migration1/testdata/设fileName channel.sqliteSQLitetest_db_sqlite kvdb_sqlitePostgres 承载的既有 KV 数据编辑postgresKVDSN为非空Postgreskvdb_postgres test_db_postgres补充说明两点channel.sqlite本身是 SQLite 文件但其中仍按 KV 布局bucket key/value组织支付数据因此它同样作为“KV 源”被读取迁移而不是直接当作目标表使用测试的目标 SQL 库由 test_postgres.go 与 test_sqlite.go 按构建标签二选一搭建每次运行都会新建一个干净的 SQL 数据库。操作步骤1. 放置数据库文件把你节点的channel.db或channel.sqlite复制到payments/db/migration1/testdata/目录下。测试运行时代码会基于testdata相对路径拼接文件名日志会打印Connecting to channel DB at: testdata/channel.db见 migration_external_test.go。README 提醒不要提交生产数据文件仅保留在本地。2. 修改测试代码中的两处开关编辑 migration_external_test.go// 注释掉这一行以启用测试 t.Skipf(skipping test meant for local debugging only) // 设置为你数据库的文件名 const fileName channel.db // or channel.sqlite // 若要从 Postgres 承载的 KV 源迁移设为非空 DSN const postgresKVDSN const postgresKVPfx channeldb三个可选常量的作用fileName决定打开 bbolt 还是 SQLite 文件判断逻辑是后缀是否为.sqlite见 migration_external_test.gopostgresKVDSN非空时优先走 Postgres 源DSN 会被strings.TrimSpace处理后传入kvdb.Open留空则回退到本地文件见同文件 connectPostgrespostgresKVPfxPostgres 源中支付数据所在的 kvdb 前缀默认channeldb。3. 运行测试# bbolt channel.db → PostgresREADME 基础命令 go test -v -tagstest_db_postgres -run TestMigrationWithExternalDB # channel.sqlite → SQLite go test -v -tagstest_db_sqlite kvdb_sqlite \ -run TestMigrationWithExternalDB # Postgres 承载的 KV 源 → Postgres go test -v -tagskvdb_postgres test_db_postgres \ -run TestMigrationWithExternalDB关于-v迁移过程与深校验阶段会打印进度日志如Progress: N payments, ... | ETA: ...、Deep validated x/y payments-v可以让你实时观察迁移进度批量大小由 SQL 查询配置的MaxBatchSize决定对应--max-batch-size配置项见 sqldb/paginate.go并同时用于迁移期间的批量校验与最终逐批深比较。测试内部发生了什么TestMigrationWithExternalDB的运行流程见 migration_external_test.gosetupTestSQLDB(t)基于当前构建标签创建一个全新的目标 SQL 存储在单个 SQL 事务内调用MigratePaymentsKVToSQL若中途失败则整体回滚保证原子性事务提交后调用deepValidateAllPayments做分批深比较从 KV 侧逐条读取原始支付fetchPayment按MaxBatchSize攒批后在同一个 SQL 读事务里用FetchPaymentsByIDs等批量查询拉回完整 SQL 数据含 HTLC、路由跳、自定义记录逐字段与 KV 数据做require.Equal全等比较见 deepCompareBatch。需要留意的是源码注释明确指出该测试并不是对所有支付存储类型的完整迁移测试而是供开发者/用户用真实数据库排查迁移问题的调试工具见 migration_external_test.go。迁移引擎的原理从源码看它如何保证数据不丢MigratePaymentsKVToSQLsql_migration.go是迁移核心其设计要点按序流式迁移先扫描 KV 中的 index bucketpaymentsIndexBucket拿到每个支付序号到哈希的映射再按序号顺序逐条迁移而不是直接遍历 payments bucket——因为后者会得到哈希的字典序而非支付创建的时序见同文件collectMigrationState与migrateIndexEntrysql_migration.go 和 sql_migration.go。单元测试TestMigrationSequenceOrder专门验证了这一时序保证sql_migration_test.go。进度与 ETA 上报migrationProgressReporter以 5 秒间隔打印迁移速率与滚动窗口 ETA便于长迁移时观测sql_migration.go。重复支付单独落表KV 中同一哈希下的多个重复支付会被迁移进独立的payment_duplicates表并在摘要中单独统计DuplicatePayments/DuplicateEntries见 sql_migration.go。TestMigrationWithDuplicates与TestDuplicatePaymentsWithoutAttemptInfo覆盖了有/无 attempt 信息两类重复支付的迁移结果sql_migration_test.go。遗留 attempt ID 修复SQL 表要求payment_htlc_attempts.attempt_index全局唯一而非常古老的 KV 支付中 attempt ID 可能为 0旧迁移写入的“未知”值。迁移会从 switch sequencer 的持久化水位switchNextPaymentIDKey分配新的合成 ID并在迁移成功后把水位前推确保未来运行时不会发出与已迁移 attempt 冲突的 ID见newAttemptIDAllocator与advanceSwitchPaymentIDSequencesql_migration.go。相关行为由TestMigrationWithLegacyZeroAttemptIDs验证sql_migration_test.go。无法恢复的 in-flight 遗留尝试被终止对于 attempt ID 为 0 且既无 settle 也无 failure 的进行中 HTLC迁移会将其标记为失败并把父支付置为失败因为迁移后在线 switch 状态无法再恢复这种未知 ID 的尝试terminalizeUnresolvedLegacyZeroAttemptssql_migration.go。路由数据逐项落列MPP、AMP、blinded route加密接收者数据 盲化点 总额、自定义记录等都被拆到各自子表对“有盲化点却无加密数据”的畸形 hop 直接报错对“无加密数据但带孤立盲化总额”的 hop 则告警并忽略总额见 migrateRouteHop。MPP/AMP/blinded/custom records 均有对应单测sql_migration_test.go。时间戳规范化写入 SQL 前统一去掉单调时钟读数并转 UTCnormalizeTimeForSQLsql_migration.go保证跨环境比较的确定性。迁移结束后会打印一份汇总printMigrationSummary包含各状态支付数、各状态 HTLC attempt 数、路由跳总数、跳过的索引条目数、重复支付数以及迁移耗时方便快速核对是否与你预期一致。常见问题排查测试没跑TestMigrationWithExternalDB默认带有t.Skipf(skipping test meant for local debugging only)未注释该行会直接跳过——这是刻意设计防止该测试进入常规 CI 流程。“missing postgres kvdb dsn”失败postgresKVDSN非空时connectPostgres会对 DSN 做TrimSpace空串直接t.Fatalfmigration_external_test.go。索引桶缺失若 KV 库中没有paymentsIndexBucket迁移会以index bucket does not exist报错sql_migration.go。深比较报 payment mismatch迁移完成后 KV 与 SQL 两侧数据不一致会以payment mismatch %x哈希前缀失败并打印批次上下文migration_external_test.go这正是本测试最有价值的输出——它直接告诉你哪笔支付在哪个字段上迁移异常。局限与适用前提本测试主要面向本地调试它要求testdata/下存在真实数据库文件并依赖test_db_postgres/test_db_sqlite等仅测试期可用的构建标签因此在 LND 正式构建流程中不可用正如源码注释所述它不覆盖所有支付存储类型只针对上述三种 KV 源迁移源以只读方式打开目标 SQL 库每次新建因此该测试对原节点数据是无副作用的可以放心在拷贝出的数据库副本上反复执行。赞分享区块链【免费下载链接】lndLightning Network Daemon ⚡️项目地址https://gitcode.com/gh_mirrors/ln/lnd点击查看免费下载相关推荐LND v0.21.0 支付数据迁移实战指南Payments KV → SQL 迁移的测试流程、风险控制与故障排查LND v0.21.0 支付数据迁移实战指南Payments KV → SQL 迁移的测试流程、风险控制与故障排查 导读 本文以 LND v0.21.0 的支区块链终极轮播解决方案为什么Slick是你最需要的最后一个轮播库终极轮播解决方案为什么Slick是你最需要的最后一个轮播库 还在为网页轮播组件头疼吗每次项目需要轮播功能时你是否都在重复造轮子今天我们来聊聊Slick—UI组件前端Hyperswitch数据迁移支付历史数据迁移实战指南Hyperswitch数据迁移支付历史数据迁移实战指南 引言支付数据迁移的挑战与机遇 在支付系统演进过程中数据迁移是不可避免的关键环节。Hyperswit后端金融科技上一篇3步完成Windows HEIC缩略图预览告别iPhone照片无法预览的烦恼下一篇D3KeyHelper暗黑破坏神3终极宏工具完全指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考