Bisq BSQ Swap 卖家输入校验规范:买家如何安全验证卖家 BTC 输入并签名

发布时间:2026/10/14 2:55:45

Bisq BSQ Swap 卖家输入校验规范:买家如何安全验证卖家 BTC 输入并签名 区块链DeFi金融科技【免费下载链接】bisqA decentralized bitcoin exchange network项目地址https://gitcode.com/gh_mirrors/bi/bisq点击查看免费下载导读本文深入解读 Bisq去中心化比特币交易所BSQ Swap 协议中的一份关键安全规范——bsq-swap-seller-inputs.md。该规范定义了在买家对最终 swap 交易签名之前必须如何验证卖家BTC 卖家的每一笔交易输入以及卖家在选币时不得选用哪些输出。读完本文你将掌握 BSQ Swap 交易中输入描述的传输格式RawTransactionInput、输入描述必须与实际花费输出严格绑定的安全不变量、卖家签名形式白名单P2PK/P2PKH/P2WPKH、DAO 状态下 BSQ 输出的排除规则以及买家侧校验在源码中的完整实现ProcessBsqSwapFinalizeTxRequest、TransactionValidation并了解该规范的兼容性与明确不覆盖的边界。适用范围与协议上下文BSQ Swap 是一笔同时包含 BSQ 着色输入与 BTC 输入的单笔 Bitcoin 交易买家贡献 BSQ 输入卖家贡献 BTC 输入卖家收到 BSQ买家收到 BTC任何未分配给输出的输入值成为 Bitcoin 矿工费。本规范约束的是买家BTC 的买方视角且无论买卖双方是 maker 还是 taker 均适用。协议流程中卖家构建 swap 交易并连同每个输入的描述信息一起发给买家买家依据描述验证卖家是否支付了其应承担的矿工费份额、是否未拿走超出应得的找零验证通过后买家才对自己的输入签名、广播并回传交易。关于费用如何分担矿工费 vs 交易费详见 docs/bsq-swap-fee-handling.md。卖家对买家输入的校验不在本规范范围内——卖家是自己根据买家的输入描述构建交易因此买家输入天然与其描述绑定卖家对买家签名合法性的校验由 docs/specifications/trade/bsq-swap-buyer-signatures.md 规定。从源码消息结构看卖家输入描述通过BsqSwapFinalizeTxRequest传输见 BsqSwapFinalizeTxRequest.java其字段包括tx卖家构建的已部分签名swap 交易序列化字节btcInputs卖家各 BTC 输入的描述列表btcChange卖家 BTC 找零金额bsqPayoutAddress卖家 BSQ 收款地址btcChangeAddress卖家 BTC 找零地址。单个输入描述由RawTransactionInput承载见 RawTransactionInput.java对应规范所述的四项要素字段含义parentTransaction被花费输出所在父交易的序列化字节index被花费输出在父交易中的输出索引value该输出的金额聪scriptTypeId该输出脚本类型 id用于判断是否为 segwit例如 P2WPKH/P2WSH安全不变量输入必须严格花费描述所指的输出核心不变量买家签名前交易的每个卖家输入必须恰好花费其对应描述所指定的输出——相同的父交易 ID、相同的输出索引且与描述的顺序一一对应。所有使用卖家输入金额或脚本类型的校验都必须以该输入实际花费的输出为准。为什么买家自己的签名不足以保护自己买家的签名会承诺所有输入的outpoint但不会承诺卖家输入的金额。如果卖家输入可以花费与描述不同的输出卖家就能构造攻击描述同一父交易中金额较大的输出实际却花费该交易中金额较小的输出买家按描述的大金额校验矿工费与找零卖家便可以从矿工费包括买家自己的份额中找回多余的找零。该攻击的杠杆被进一步放大taker 可以选择高达maker 本地费率估算两倍的费率由MinerFeeValidation.checkMinerFeeRateIsInTolerance控制见 MinerFeeValidation.java 中MAX_FEE_DEVIATION_FACTOR 2。当买家是 maker 时其承担的费率份额会更大。三条规则规范将不变量落为三条可执行的规则父交易 ID 绑定输出父交易 ID 由描述中的父交易计算得出而父交易 ID 承诺了其全部输出。因此只要输入花费的正是描述的 outpoint其金额与脚本类型就必然等于描述输出。输入数量一一对应交易中每个描述都必须有一个卖家输入且这些输入位于买家输入之后。禁止重复花费同一 outpoint否则同一描述可以列出两次其金额被重复计数两次。源码中的落实ProcessBsqSwapFinalizeTxRequest买家侧验证集中在 ProcessBsqSwapFinalizeTxRequest.java。其关键步骤checkTransaction解析并验证卖家交易Transaction.verify()同时拒绝重复花费同一 outpoint 的交易规则 3 的源码实现input.validate(btcWalletService)校验描述中 value/scriptTypeId 与父交易对应输出一致防描述虚高的静态校验checkInputOutpoints逐一比对交易输入的实际 outpoint 与描述 outpointgetHash()与getIndex()必须同时相等并且要求交易中的卖家输入数量与描述数量相等规则 1、2 的源码实现校验卖家输入金额总和是否不低于本地按交易大小与费率计算出的getSellersBtcInputValue校验卖家找零btcChange expectedChange确保卖家没有从矿工费中窃取详细费用公式见下文。其中checkInputOutpoints与checkInputSignatures均在 TransactionValidation.java 中实现并有对应单元测试 TransactionValidationTest.javacheckInputOutpointsAcceptsInputWhichSpendsTheExpectedOutpoint花费预期输出则通过checkInputOutpointsRejectsOtherOutputOfTheExpectedParentTransaction同一父交易中花费另一个输出则被拒绝checkInputOutpointsRejectsOutputOfAnotherParentTransaction花费另一个父交易的输出则被拒绝。BSQ 输出不得作为卖家输入规则卖家只能用 BTC 支付买家签名前任何卖家输入都不得花费买家 DAO 状态中记录为未花费 BSQ 输出的输出。为执行该规则买家的 DAO 状态必须就绪且已同步否则买家直接拒绝该请求源码中为daoFacade.isDaoStateReadyAndInSync()检查。DAO 状态必须同步的原因源码注释亦明确花费硬分叉 3 高度起的lockup 输出见 docs/specifications/dao/bond-lockup-spend.md或花费锁定期未过的 unlock 输出会使整笔交易对 DAO 而言无效无效交易的全部 BSQ 输入被烧毁、任何输出都不会成为 BSQ 输出买家将失去自己的 BSQ 找零。规则按输入实际花费的输出评估如同安全不变量所要求的该 BSQ 排除规则也必须基于输入实际花费的输出来评估。如果只检查描述输出攻击者可以描述同一父交易中的 BTC 输出实际却花费其 BSQ 输出从而绕过检查。源码中的实现方式对每个sellersRawBtcInputs构造TxOutputKey(parentTxId, index)并断言!daoFacade.isUnspentTxOutput(key)。注意 key 的父交易 ID 通过input.getParentTxId(btcWalletService)从序列化的父交易解析而来这与父交易 ID 承诺其输出的原理一致。什么输出不算 BSQ 输出BSQ 交易中被 DAO 归类为 BTC 输出的输出不属于 BSQ 输出卖家可以花费。典型例子一笔以 BSQ 支付交易费的交易的 BTC 找零输出。卖家的镜像规则选币时排除 BSQ 输出卖家在选择自己的 BTC 输入时既用于 swap 交易本身也用于资金估算必须应用同样的规则不选择其 DAO 状态记录为未花费 BSQ 输出的输出例如发送到卖家某个 BTC 地址的 BSQ。如果除这类输出外卖家的 BTC 钱包没有足够 BTC则卖家视为资金不足missing funds。该逻辑在 BsqSwapCalculation.java 中实现getSellersBtcInputsAndChange通过谓词isUnspentBsqOutput(daoFacade)过滤不可用的输出getSellersSelectableBtcBalance返回可选的 BTC 余额同样排除未花费 BSQ 输出其迭代式费用估算从MIN_SELLERS_TX_SIZE 104vBytes 起步反复用getVBytesSizesegwit 输入 68 vBytes、非 segwit 输入 149 vBytes、有找零 62、无找零 31校正所需输入最多迭代 10 次。卖家作为 taker 时处理买家 BSQ 输入消息BsqSwapTxInputsMessage的ProcessBsqSwapTxInputsMessage见 ProcessTxInputsMessage.java同样先断言 DAO 状态就绪并用 DAO 的unspentTxOutputMap交叉验证买家的每个 BSQ 输入确实存在、未花费且可花费isTxOutputSpendable。测试用例 BsqSwapSellerDaoStateGuardTest.java 验证了 DAO 状态未同步时seller-as-maker 与 seller-as-taker 均会以 DAO state is not ready and in sync 拒绝请求。卖家签名形式白名单严格校验只有三种输出类型、固定签名形式买家签名前每个卖家输入必须处于卖家钱包签名的形式且签名对花费输出的金额与脚本有效。Bisq 钱包只签 P2PK、P2PKH、P2WPKH 三类输出且一律使用 SIGHASH_ALL形式固定输出类型合法形式P2WPKH空 scriptSigwitness 中恰好包含签名与压缩公钥两项 pushP2PKHscriptSig 中恰好包含以最短 push 编码的签名与公钥无 witnessP2PKscriptSig 中恰好包含以最短 push 编码的签名无 witness公钥必须是压缩或非压缩的标准编码网络不会中继混合编码hybrid公钥。买家拒绝其他任何形式。该白名单正是卖家钱包签名的产物。对照 TradeWalletService.java 的signInputP2PK/P2PKH 走hashForSignature(..., SIGHASH_ALL, false)ScriptBuilder.createInputScriptP2WPKH 走calculateWitnessSignatureredeemP2WPKH空 scriptSig witness其余脚本类型直接抛出SigningException(Dont know how to sign...)。买家侧的镜像校验买家侧的checkInputSignatures源码注释逐字对应本规范通过isSignedInBisqWalletForm校验P2WPKHscriptBytes.length 0、witness 恰好 2 项 push、签名末字节为 SIGHASH_ALL、公钥 push 长度为 33 字节压缩P2PK/P2PKH无 witness、scriptSig push 数分别为 1/2、所有 push 均为最短编码isShortestPossiblePushData、签名带 SIGHASH_ALL再通过Script.correctlySpends(..., Script.ALL_VERIFY_FLAGS)用花费输出的金额与脚本实际验签。为什么只验这三种类型就够了Script.correctlySpends只为上述类型验证签名而且即便如此也不覆盖网络的全部规则例如witness 项数、witness 签名的 ANYONECANPAY 标志scriptSig 的中继规则。因此一个被网络拒绝或不中继的卖家输入会让买家拿到一笔永不确认的交易。若卖家之后能修正该输入这也会给卖家留下与未签名输入相同的主动权详见下文未覆盖部分。SIGHASH_ALL 签名的覆盖范围卖家输入使用的 SIGHASH_ALL 签名覆盖所有输入的 outpoint 与所有输出但不覆盖买家输入的脚本与 witness。因此买家随后对自己输入签名不会使卖家的签名失效——这正是两阶段签名流程卖家先签、买家后签能够成立的前提。测试用例checkInputSignaturesAcceptsValidP2wpkhSignature/checkInputSignaturesAcceptsValidP2pkhSignature/checkInputSignaturesRejectsMissingSignatureTransactionValidationTest.java分别验证了这两类合法形式通过、缺失签名被拒绝。这一规则防止买家签出一笔因卖家输入而残缺的交易但并未剥夺卖家事后决定 swap 是否发生的选项——使用一笔尚未发布的父交易作为输入具有相同的效果且买家无法察觉见下文。买家签名与交易一致性交叉校验买家侧在 BuyerCreatesAndSignsFinalizedTx.java 中用本地数据重新构建完整交易买家 BSQ 输入、卖家 BSQ 收款、双方找零、买家 BTC 收款等全部取自本地模型而非直接信任卖家消息然后checkArgument(Arrays.equals(transaction.bitcoinSerialize(), tradePeer.getTx()), Buyers unsigned transaction does not match the sellers tx);若序列化结果与卖家发来的交易不一致则拒绝签名。换言之BsqSwapFinalizeTxRequest中仅卖家的 BTC 输入被原样采用交易其余部分由买家重建并与卖家交易逐字节比对。这保证了费用与找零金额以本地按费率、交易大小计算的期望值为准卖家无法通过捏造交易结构窃取买家份额买家输入的脚本/witness 差异不影响比对因为卖家部分签名中买家输入为空。同时买家在 BuyerPublishesTx.java 中通过publishAndCommitBsqTx广播交易并在广播结果未知前即回传BsqSwapFinalizedTxMessage给卖家广播超时按成功处理——这是本规范明确不覆盖、由协议设计承担的风险见下文。费用校验如何依赖输入绑定不变量买家对卖家输入的金额校验ProcessBsqSwapFinalizeTxRequest中的expectedChange计算依赖 docs/bsq-swap-fee-handling.md 所述的分担模型adjustedTxFee max(0, txFeePerVbyte * 该方vBytes - 该方BSQ交易费)买家 BSQ 输入 bsqTradeAmount buyersTradeFee买家 BTC 收款 btcTradeAmount - adjustedBuyerTxFee卖家 BTC 输入 btcTradeAmount adjustedSellerTxFee卖家 BSQ 收款 bsqTradeAmount - sellersTradeFee。买家校验时用**卖家输入描述已绑定实际花费输出**的金额之和减去本地算出的买家 BTC 收款与双方调整后交易费得到expectedChange并断言change expectedChange——只允许找零小于等于期望值dust 找零、币选择溢出会落入矿工费绝不允许大于期望值那意味着卖家回收了本该付矿工费的钱。注释明确写道By enforcing that it must not be larger than expectedChange we guarantee that peer did not cheat on tx fees.兼容性所有版本的诚实卖家都用自己的描述构建输入因此本规范的绑定规则不会拒绝诚实交易消息结构与持久化数据均未变化。旧版本卖家在选币时不排除 BSQ 输出可能选中其 BTC 钱包持有的 BSQ 输出。新买家拒绝此类请求而不是签出一笔改变 DAO 解析方式的交易。买家在处理卖家请求时新增了对DAO 状态就绪且同步的检查。未覆盖的范围与已知边界规范明确列出以下不属于本规范解决的攻击面理解它们有助于正确评估 BSQ Swap 协议的整体信任模型SPV 钱包限制买家使用 SPV 钱包无法验证卖家输入是否存在、是否未花费、是否已确认。卖家因此可以拖延或阻止swap 确认——例如使用一笔尚未发布或日后被替换的父交易作为输入买家钱包将显示一笔永不确认的 swap。DAO 状态尚未收录的输出未被 DAO 状态收录的输出例如父交易尚未确认不会被识别为 BSQ 输出——买家校验与卖家选币均无法察觉。广播时序买家在广播结果未知前就将交易提交至钱包并回传卖家广播超时按成功处理因此一笔被网络拒绝的交易仍可能在买家侧被标记为交易完成。taker 费率容忍度不调整taker 选择费率maker 接受其自身估算一半到两倍之间的费率MinerFeeValidation.checkMinerFeeRateIsInTolerance。在本规范的不变量下卖家无法从矿工费中拿回任何部分但接手买家挂单的卖家仍可让买家按最高两倍估算费率支付份额且该份额随买家输入与找零输出规模增大多付部分归矿工卖家按相同费率支付自身份额。该容忍度使费率估算不同的交易者可以相互成交收紧它会拒绝今天可接受的成交因此是否调整属于维护者的决策不随本变更进行。总结一份从消息到签名全链路可验证的规范bsq-swap-seller-inputs.md是 BSQ Swap 双人签名流程中买家侧安全的基石。它通过输入描述与实际花费输出严格绑定的安全不变量、DAO 状态下的 BSQ 输出排除、以及 P2PK/P2PKH/P2WPKH 签名形式白名单三组规则配合仓库中 ProcessBsqSwapFinalizeTxRequest.java、TransactionValidation.java、BsqSwapCalculation.java 等实现与 TransactionValidationTest.java 等测试确保买家在签名前即可判定卖家付出了应承担的矿工费、没有从交易费中窃取找零、输入完整可确认且交易在买家签名后立即可广播。同时规范也诚实地划定了 SPV 钱包、DAO 收录时序与广播时序等协议层面的固有边界为审计与后续演进提供了清晰的参照。赞分享区块链DeFi金融科技【免费下载链接】bisqA decentralized bitcoin exchange network项目地址https://gitcode.com/gh_mirrors/bi/bisq点击查看免费下载相关推荐Bisq BSQ Swap 买家签名校验规范如何防止无效签名与重复输入提交Bisq BSQ Swap 买家签名校验规范如何防止无效签名与重复输入提交 导读 本文解读 Bisq 去中心化交易所中 BSQ SwapBSQ 兑 BTC区块链DeFi金融科技financial-services 仓库 investment-banking 插件 buyer-list 技能实战构建卖单并购的买家名单与买家宇宙financial services 仓库 investment banking 插件 buyer list 技能实战构建卖单并购的买家名单与买家宇宙 导读人工智能AI 应用AI 技能/插件AI Agent金融科技如何让十年老电脑重新流畅低成本翻新与性能优化实战指南如何让十年老电脑重新流畅低成本翻新与性能优化实战指南 桌上那台开机要等两分钟、硬盘灯常年不熄的老机器真的只能进闲鱼吗未必。这篇低成本旧电脑升级实战指南给操作系统固件驱动开发上一篇小红书作品批量下载3种方法轻松实现自动化采集下一篇小红书内容下载完整指南3种方法轻松获取高质量作品创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/10/14 2:55:45

Git与Node.js开发环境搭建与高频命令实战指南

写这篇东西,是因为最近团队里新来了几个小伙伴,配置开发环境时遇到的问题一个接一个——版本对不上、命令找不到、代码提交后后悔想回退却不知道怎么操作。其实Git和Node.js是现在做开发几乎绕不开的两样东西,一个是版本控制的事实标准&#…

2026/10/14 2:55:45

C语言教务系统课程设计:结构体+链表+CSV文件实战

简介:本资源是一份完整的C语言课程设计实践项目——教务信息管理系统,面向计算机专业本科生及C语言初学者,解决课程设计中系统化开发、链表综合应用与图形化交互实现等核心问题。压缩包为单个361KB的Word文档(.doc)&am…

2026/10/14 2:55:45

Akka Typed消息协议设计:从ActorRef到状态机实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 4:00:48

生产级公司官网HTML模板:SEO友好、无障碍、Lighthouse 90+

简介:本资源是一套开箱即用的科技公司官网HTML页面模板,面向前端初学者与中小型项目开发者,解决企业官网快速搭建、响应式布局实现及基础交互功能集成等实际需求。压缩包共48个文件,含5个结构清晰的HTML主页面(首页、关…

2026/10/14 4:00:48

威胁情报月报与安全技术更新:从情报到处置的完整闭环

十二月写威胁情报月报,感觉和其他月份很不一样。平时写的是“这段时间什么攻击变多了、哪个软件出了风险、我们哪些规则可以更新”,到了十二月,同样的工作自动增加了一层含义:它既是本月复盘,也是全年安全运营的交接点…

2026/10/14 4:00:48

基于VS+Qt+FFmpeg的视频播放器架构与音画同步实战

简介:这份压缩包是基于VS与Qt开发的视频播放器练习项目,面向刚接触Qt界面编程或VS环境下C开发的初学者。项目实现了从文件夹选取视频、播放、暂停等基础功能,整体代码结构简洁,适合作为GUI编程入门参考。包内共45个文件&#xff0…

2026/10/13 5:19:27

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/13 17:09:18

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/14 2:32:55

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/14 0:00:33

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:33

macOS/iOS高精度计时:mach_absolute_time原理与实战

1. 项目概述:为什么mach_absolute_time是 macOS/iOS 时间测量的“黄金标准”在 macOS 和 iOS 开发中,我见过太多人用CFAbsoluteTimeGetCurrent()或NSDate.timeIntervalSinceReferenceDate做性能打点,结果在高精度场景下被系统时钟跳变、NTP 同…

2026/10/14 0:00:33

SCORM课件演示与测试全解析:从API通信到自动化验证

简介:这是一套遵循SCORM标准的交互式课件演示与测试资源,面向E-Learning课程开发者、LMS平台测试人员及在线教学从业者,用于验证课件在不同学习管理系统中的识别、传递与跟踪能力。压缩包共28个文件,约12.07MB,以swf动…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑