bips/bip-XXXX.mediawiki,位于betterhash · TheBlueMatt/bips

该文档提出了一种名为BetterHash的新的比特币挖矿协议,旨在改进现有Stratum协议的不足,通过分离工作信息和矿池支付信息的通道,提高挖矿的去中心化程度,并提升矿池的效率和安全性。该协议包括工作协议和矿池协议,分别处理挖矿任务的分配和矿工的收益分配,同时定义了详细的消息格式和通信流程。

跳至内容

TheBlueMatt/ bips 公开

fork 自 bitcoin/bips

折叠文件树

文件

betterhash

在此仓库中搜索

/

bip-XXXX.mediawiki

复制路径

追溯更多文件操作

追溯更多文件操作

最新提交

TheBlueMattTheBlueMatt

添加挖矿协议 BIP 草案

2018年7月18日

02f7040 · 2018年7月18日

历史

历史

打开提交详情

查看此文件的提交历史。

822 行 (736 loc) · 83.4 KB

/

bip-XXXX.mediawiki

顶部

文件元数据和控件

  • 预览

  • 代码

  • 追溯

822 行 (736 loc) · 83.4 KB

Raw

复制原始文件

下载原始文件

你必须登录才能进行或提议更改

更多编辑选项

大纲

编辑和原始操作

  BIP: XXXX
  Layer: API
  Title: BetterHash Mining Protocol(s)
  Author: Matt Corallo
  Status: Draft
  Type: Standards Track
  Created: 2018-03-12
  License: BSD-2-Clause
## 目录<br>固定链接: 目录<br>- 摘要<br>- 动机<br>- 协议概述<br>- 示例网络拓扑 <br> - 大型矿场<br> - 基于广播的矿场<br> - 简单但高效的矿池架构<br>- 工作协议规范 <br> - 消息定义 <br> - PROTOCOL_SUPPORT<br> - PROTOCOL_VERSION<br> - ADDITIONAL_COINBASE_LENGTH<br> - BLOCK_TEMPLATE<br> - WINNING_NONCE<br> - TRANSACTION_DATA_REQUEST<br> - TRANSACTION_DATA<br> - COINBASE_PREFIX_POSTFIX<br> - BLOCK_TEMPLATE_HEADER<br> - WINNING_NONCE_HEADER<br> - NEW_WORK_SERVER<br> - VENDOR_MESSAGE<br>- 广播媒介上的最终工作协议<br>- 矿池协议规范 <br> - 消息定义 <br> - PROTOCOL_SUPPORT<br> - PROTOCOL_VERSION<br> - PAYOUT_INFO<br> - USER_AUTH<br> - ACCEPT_USER_AUTH<br> - REJECT_USER_AUTH<br> - DROP_USER<br> - SHARE_DIFFICULTY<br> - SHARE<br> - WEAK_BLOCK<br> - WEAK_BLOCK_STATE_RESET<br> - SHARE_ACCEPTED<br> - SHARE_REJECTED<br> - NEW_POOL_SERVER<br> - VENDOR_MESSAGE<br>- 讨论<br>- 致谢

摘要

固定链接: 摘要

我们提出了两种新的挖矿协议,以重新思考比特币网络中生成工作的方式,从而有可能大幅提高有效挖矿的去中心化程度。

本文档中的关键词“必须”,“禁止”,“需要”,“应该”,“不应该”,“推荐”,“可以”和“可选”应按照 RFC 2119 中的描述进行解释。

动机

固定链接: 动机

比特币挖矿领域存在许多鼓励中心化的压力。 维持这些压力的一个载体是通过最广泛部署的挖矿协议:Stratum。 Stratum 协议难以实施且文档记录不完善,因此矿池运营商需要构建区块模板并将其分发给客户端。 如果没有各种矿工构建区块模板,网络的抗审查性将受到威胁(例如,矿池运营商可能会利用其权力来限制协议升级的流程)。 由于服务器和客户端之间缺少密码学认证的连接,进一步加剧了对这些中心化力量的担忧,这是一个时间攻击的载体(例如,MiTM),恶意方可以通过该载体以静默方式获得对算力的控制,直到矿池运营商和/或其他矿工进行干预。 此外,Stratum 客户端的简单实施要求每个矿工都指向一个常用的 Stratum 服务器,从而导致大量单独的连接涌入每个矿池。

还存在对 Bitcoin Core API 的广泛依赖,以向矿工提供新工作并监视区块更新,这是矿池运营商必须以非凡的实施复杂性来管理的负担。 例如,除非以不受支持的方式利用 Bitcoin Core API,并且依赖 Bitcoin Core 中通知的内部排序(从而损害了性能),否则 getblocktemplate 的长轮询的实现既效率低下又不可靠。 此外,getblocktemplate 提供的数据量和性质使协议升级变得复杂,并迫使矿池服务器对交易进行哈希处理以构建区块的 Merkle 树。 更糟糕的是,由于其基于轮询的架构,阻止了解决 getblocktemplate 的延迟问题的尝试。

该提案解决这些缺陷的主要机制是通过分离工作信息和矿池支付信息所承载的通道。 当直接传递到挖矿硬件时,工作承载协议将替换 getblocktemplate 和 Stratum,而支付协议会管理所有池<->客户端通信。 这些功能的隔离为矿池参与者提供了构建区块模板的能力,这些区块模板包含他们(或他们选择的另一个矿池)选择的交易,而矿池会监督支付的分配。 在此提案之前,希望构建自己的模板的矿工必须进行单人挖矿或加入 p2pool,这两种方式的支付差异都很大。 借助 BetterHash,矿工既可以降低其支付差异,又可以构建自己的区块模板。

BetterHash 的可扩展性也值得注意,因为它的结构更依赖 Bitcoin Core 中的模板逻辑,而不是其前身 getblocktemplate。 该切换提高了性能,简化了向新共识规则的过渡,并允许更强大的模板逻辑(例如,更好的mempool逐出)。 池的整体架构也简单得多,因为可以以更低的开销添加其他服务器(因为工作由客户端管理)。 除了对代理的一流支持之外,这还有助于缓解连接泛滥。

虽然完全替换 Stratum 协议可能并非实现既定目标所必需的,但所需的架构更改提供了一个解决 Stratum 长期存在的问题的机会。 在这种情况下,协议的整体重写似乎比额外的 Stratum 扩展更有利。

协议概述

固定链接: 协议概述

工作协议以三种模式之一将新的唯一工作推送到客户端。“非最终”工作模式是不包含支付的工作,并且描述了如何构建 coinbase 交易,以及涵盖区块中交易和区块头信息的 Merkle 路径。 客户端可以使用“非最终”工作来生成支付给矿池服务器的工作。“最终”工作信息非常相似,但包括完整的支付信息,旨在发送给硬件控制器进行挖矿。“头部”工作假设客户端能够滚动 nVersion 字段以及区块头部中的 nonce 足够多次,以生成整整一秒钟的工作,从而允许他们通过每秒滚动一次头部 nTime 字段来饱和他们的工作。 对于此类客户端,无需发送 coinbase 交易或 Merkle 路径信息,从而大大简化了协议(这显然意味着“最终”工作,因为客户端无法填写 coinbase 交易中的支付信息)。

矿池协议相对简单,主要侧重于将 PAYOUT_INFO 消息发送给可用于构建“最终”工作的客户端。 客户端将 SHARE 发送到矿池作为工作量证明,从而允许他们获得合并奖励。 矿池协议具有一个可选的附加功能,适用于希望优化区块传播的矿池,即客户端将 WEAK_BLOCK 发送到矿池服务器,以便高效上传完整区块。

两种协议都以 PROTOCOL_SUPPORT/PROTOCOL_VERSION 握手开始,服务器(矿池或工作)在握手完成后立即发送初始 COINBASE_PREFIX_POSTFIX+BLOCK_TEMPLATE(对于工作服务器)或初始 PAYOUT_INFO+SHARE_DIFFICULTY(对于矿池服务器)。 此后,服务器可以根据需要将更新推送到工作/支付/难度信息,客户端通过 WINNING_NONCE 或 SHARE/WEAK_BLOCK 消息提交有效份额。

示例网络拓扑

固定链接: 示例网络拓扑

本节不具有规范性,但提供了一些预期部署场景的示例。

大型矿场

固定链接: 大型矿场

     ASICs ASICs ASICs ASICs
        \    |     |    / (通过 stratum 或工作协议)
     农场代理/挖矿控制器
    / (通过工作协议)      \ (通过矿池协议)
 本地 bitcoind                 远程矿池

在此设置中,挖矿控制器(例如,廉价的基于 ARM 的服务器)接受来自 ASIC 矿机的传入连接。 这些连接可以使用 stratum(为了向后兼容)或新的工作协议(可选地以头部模式,这大大简化了 ASIC 级别的逻辑 - 允许 ASIC 固件甚至跳过实现 Merkle 路径哈希/coinbase 交易构造逻辑)。 该挖矿控制器通过工作协议(从不在头部模式)从本地 bitcoind(可选地在同一设备上,为了简单起见)获取工作,并使用矿池协议连接到一个或多个远程矿池。 借助来自 bitcoind 的 BLOCK_TEMPLATE 和来自矿池服务器的 PAYOUT_INFO,挖矿控制器可以构建独特的矿工,这些矿工向矿池支付费用,但包含本地节点选择的交易以进行分发给 ASIC。 满足矿池 SHARE_DIFFICULTY 的 share_target 的区块将(仅包含 coinbase 交易、Merkle 路径和区块头)发送到矿池,以进行验证和支付,并且满足比特币网络难度的区块将发送到本地 bitcoind。 矿池可以选择请求以辅助难度发送完整区块(使用基于弱区块的压缩方案),以便矿池也能收到用于中继的完整难度区块。

基于广播的矿场

固定链接: 基于广播的矿场

待办事项

简单但高效的矿池架构

固定链接: 简单但高效的矿池架构

待办事项:关于只有一个矿池服务器很棒,因为你可以通过矿池协议多路复用多个客户端,因此你可以在全球范围内拥有大量 stratum 代理 + bitcoind 以提高效率,然后只拥有一个(或两个,用于冗余/GFW 问题)集中/安全托管的矿池服务器,从而大大简化了矿池的管理和安全性。

工作协议规范

固定链接: 工作协议规范

  1. 所有消息都在线路上序列化,前缀为 1 字节的 message_type,然后是 message_length(作为 3 字节整数,不包括 message_typemessage_length 字段),然后是消息本身。 除非另有说明,否则所有数字都编码为小端序。
  2. 节点禁止在消息中发送任何多余的数据。 定义为具有恒定大小长度的消息必须使用指定的精确长度进行编码。
  3. 该协议以版本握手开始,“客户端”(即工作接收器)发送 PROTOCOL_SUPPORT 消息,“服务器”(即工作提供程序)以 PROTOCOL_VERSION 响应。
  4. PROTOCOL_VERSION 消息包括一个 public_key,该 public_key 将用于签署从服务器发送到客户端的各种其他消息。
    • 客户端必须至少实现一次信任(Trust-On-First-Use)身份验证机制,并使用提供的 public_key 对来自同一工作提供商的任何剩余消息进行身份验证,即使在断开连接/重新连接期间,也要在一个会话中。
    • 客户端可以允许用户指定预期的 public_key。 如果客户端允许这样做,则应该允许用户通过输入 bech32 编码的 public-key 的 hash160@ip-or-host:port 格式的工作提供程序来指定预期的 public_key(例如 tb1qps9dq95rz7cramm0pjka0pd2tv8qrjyjj6y4me@1.1.1.1:8888)。
    • 客户端应该提供 UI 公开的 TOFU 状态重置机制(即重新连接并允许服务器提供任何公钥)。 客户端可以仅在断电循环时执行此操作(例如,仅将 TOFU 状态存储在内存中,而不将其持久存储到非易失性存储器中)。
    • 服务器必须将与 public_key 对应的私钥持久存储到非易失性存储器中,并持久地使用同一密钥。
    • 当前,仅定义了 flags 中索引为 6 和 7 的位(即序列化为 16 位小端数字时的低两位),客户端应该将所有其他位设置为 0。
    • 接收到在 PROTOCOL_SUPPORT flags 中设置的未知位的服务器应该简单地忽略它们,并且不将其包含在响应的 PROTOCOL_VERSION flags 中。
    • 如果在 PROTOCOL_VERSION flags 中设置了第 7 位,则服务器必须在每个 BLOCK_TEMPLATE 消息中将 coinbase_tx_remaining_value 设置为 0,并在 coinbase_tx_outputs_to_append 中完全声明任何 coinbase 交易奖励。 如果未设置 PROTOCOL_VERSION flags 中的第 7 位,则 coinbase_tx_outputs_to_append 中所有条目的值必须为 0。
    • 如果在 PROTOCOL_VERSION 中的 flags 中设置了第 6 位,则服务器必须永不发送 BLOCK_TEMPLATE 或 COINBASE_PREFIX_POST 和 FIX 消息,而是发送 BLOCK_TEMPLATE_HEADER 消息,该消息在可能需要 BLOCK_TEMPLATE 消息时合并任何相关的 coinbase_prefix_postfix 数据。 连接中的客户端禁止发送 WINNING_NONCE 消息,而是在需要 WINNING_NONCE 消息时发送 WINNIN_NONCE_HEADER 消息。 这实际上意味着第 7 位,因为服务器必须在每个 BLOCK_TEMPLATE_HEADER 的 merkle_root 提交的 coinbase 交易中完全声明任何 coinbase 交易奖励。
    • 如果设置了 PROTOCOL_VERSION flags 中的第 6 位,则还必须设置第 7 位。
    • PROTOCOL_SUPPORT flags 中的第 6 位和第 7 位表示四组不同的可能的接受的 PROTOCOL_VERSION flags,如下表所示。 服务器禁止使用超出以下允许范围的 PROTOCOL_VERSION flags 进行响应,而是断开请求服务器不支持的模式的客户端的连接。
比特 客户端支持
0b00 客户端希望在 coinbase 中添加自己的额外数据,以及自己的支付信息。 因此,PROTOCOL_VERSION flags 中的第 6 位和第 7 位必须为 0。
0b01 客户端必须在 coinbase 中填写自己的额外数据,但无法填写自己的支付信息。 因此,PROTOCOL_VERSION flags 中的第 6 位必须未设置,而 PROTOCOL_VERSION flags 中的第 7 位必须设置。
0b10 客户端可以选择构建自己的 coinbase 交易,但正确的操作不需要它,并且无法填写自己的支付信息。 因此,PROTOCOL_VERSION flags 中的第 6 位可以为任何值,而 PROTOCOL_VERSION flags 中的第 7 位必须设置。
0b11 客户端不支持构建自己的 coinbase 交易,因此无法填写自己的支付信息。 因此,第 6 位和第 7 位都必须设置(即 0b11)。
  1. 完成版本握手后,服务器可以向客户端发送一个可选的 COINBASE_PREFIX_POSTFIX。

    • 客户端必须在对 COINBASE_PREFIX_POSTFIX 消息执行操作之前验证该消息上的 signature,断开工作提供程序并尝试在签名无效时重新连接。
    • 客户端应该验证给定的 message_timestamp 是否在可接受的范围内(即接近当前时间)。
    • 客户端必须始终将 coinbase_prefix_postfix 添加到其工作中,并且必须始终忽略 message_timestamp 低于合理范围内最高 message_timestamp 的任何 COINBASE_PREFIX_POSTFIX 消息。
    • 为了限制与往返延迟相关的解决方案拒绝,客户端应该在收到 COINBASE_PREFIX_POSTFIX 消息时刷新工作,并且服务器应该尽可能限制发送的 COINBASE_PREFIX_POSTFIX 消息的数量。
    • 服务器必须确保 coinbase_prefix_postfix 唯一地标识一个客户端。 这可确保工作不会重复,并验证来自客户端的份额提交。
    • 为了提高效率,服务器可以依赖客户端的 WINNING_NONCE 消息,该消息在同一连接上使用来自 COINBASE_PREFIX_POSTFIX 消息的 coinbase_prefix_postfixcoinbase_tx。 因此,客户端必须仅使用在提交份额的同一套接字连接上提供的 coinbase_prefix_postfix 数据。
  2. 在初始握手以及潜在的 COINBASE_PREFIX_POSTFIX 之后,必须从服务器发送到客户端一个初始的BLOCK_TEMPLATE(或BLOCK_TEMPLATE_HEADER)消息,当服务器认为当前最佳区块发生了变化时,或者当coinbase交易的总奖励发生了重大变化时,服务器应该发送新的BLOCK_TEMPLATE (或BLOCK_TEMPLATE_HEADER)消息。

    • 客户端必须在对BLOCK_TEMPLATE/BLOCK_TEMPLATE_HEADER消息执行操作之前验证该消息上的 signature,在签名无效时断开工作提供程序并尝试重新连接。
    • 客户端应该验证给定的 template_timestamp 是否在可接受的范围内(即接近当前时间)。
    • 在 BLOCK_TEMPLATE 中发送的 coinbase_prefix_postfix 和任何 coinbase_prefix 以及任何 coinbase_postfix 的总长度不得超过 92 字节(不包括长度字节)。这保证了客户端能够使用 8 个字节作为额外的 nonce 空间。
    • 由提供非最终工作的服务器(即 coinbase_tx_remaining_value 非 0 的服务器)在 BLOCK_TEMPLATE 中发送的 coinbase_prefix_postfix 和任何 coinbase_prefix 的总长度不得超过 42 字节(不包括长度字节)。 此外,任何此类非最终 BLOCK_TEMPLATE 必须有一个 0 长度的 coinbase_postfix。 这确保了在任何代理声明多达 8 个字节的空间后,矿池至少有 42 个字节的可用 coinbase_postfix 空间。
    • 对于具有与最新BLOCK_TEMPLATE/BLOCK_TEMPLATE_HEADER相同 previous_block 的旧BLOCK_TEMPLATE/BLOCK_TEMPLATE_HEADER,服务器至少必须接受 30 秒的工作。
    • 服务器可以删除与最新BLOCK_TEMPLATE/BLOCK_TEMPLATE_HEADER具有不同 previous_block 的旧BLOCK_TEMPLATE/BLOCK_TEMPLATE_HEADER上的所有工作。
    • 因此,客户端应该previous_block 更改时刷新工作,但可以以延迟的方式进行,只要延迟刷新不超过 30 秒即可。
    • 假设任何相关矿池 PAYOUT_INFO 数据的全局唯一性,服务器必须确保 BLOCK_TEMPLATE_HEADER 消息中提供的工作是全局唯一的,包括与先前关闭的连接的唯一性。
    • 假设任何相关矿池 PAYOUT_INFO 数据的全局唯一性,服务器必须确保当客户端组合 BLOCK_TEMPLATE 和 COINBASE_PREFIX_POSTFIX 消息时提供的工作是全局唯一的,包括与先前关闭的连接的唯一性。
  3. 客户端通过 BLOCK_TEMPLATE 构建 coinbase 交易和候选头部,如下所示:

  4. 客户端可以在 coinbase 字段中使用任何剩余的空间(最多 100 个字节)作为额外的 nonce 空间。 由于对 BLOCK_TEMPLATE 的 coinbase_prefixcoinbase_postfix、COINBASE_PREFIX_POSTFIX 的 coinbase_prefix_postfix 以及矿池 PAYOUT_INFO 的 coinbase_postfix 的限制,客户端保证至少有 8 个字节可用于此目的。

  5. 一旦客户端选择了其预期的额外 nonce 大小,就可以通过将最高时间戳的 BLOCK_TEMPLATE coinbase_prefix 与最高时间戳的 COINBASE_PREFIX_POSTFIX coinbase_prefix_postfix 连接起来,然后连接任何额外的 nonce 信息,然后连接 BLOCK_TEMPLATE coinbase_postfix

  6. 一旦客户端构建了 coinbase,就可以通过将 coinbase_tx_version 与 coinbase 字段的长度、构建的 coinbase 字段和 coinbase_tx_input_nSequence 连接起来来构建 coinbase 交易的第一部分。

  7. 如果 coinbase_tx_remaining_value 非 0(意味着未设置 PROTOCOL_SUPPORT flags 中索引为 7 的位),则 coinbase 交易中第一个输出应该向客户端支付整个剩余值。

  8. 然后,通过附加来自 BLOCK_TEMPLATE 的 coinbase_tx_outputs_to_appendcoinbase_locktime 来完成 coinbase 交易。 请注意,不接受任何剩余输出值的客户端可以通过简单地使用 coinbase_tx_remaining_data_len 作为长度指示符来附加消息中的所有剩余数据来执行此操作。

    
    - 提供非最终工作的服务器(即 _coinbase\_tx\_remaining\_value_ 非0)**必须不允许** _coinbase\_tx\_remaining\_data\_len_ 超过32767字节,以便为池服务器提供的任何其他输出留出空间。
    - 提供非最终工作的服务器**应该**将 _coinbase\_tx\_remaining\_data\_len_ 限制为133字节(即限制 _coinbase\_tx\_outputs\_to\_append_ 的长度为128字节),以确保具有0附加coinbase长度的最大尺寸的最终BLOCK\_TEMPLATE适合单个IPv6 TCP帧内(当使用1280字节的最小所需MTU和60字节的TCP标头时,这在现代Linux上由于SACK和时间戳选项而很常见)。
    - 字段从相关消息字段复制到候选标头中,仅未提供nonce和merkle根,merkle根将通过使用双SHA256对生成的coinbase交易的txid与 _merkle\_path_ 条目进行哈希计算得出,这是Bitcoin共识规则所要求的。
    - 客户端**可以**更改BIP YYYY(TODO:Drak的BIP)保留的块头版本字段位,并在生成工作时每秒将块头时间戳递增1。客户端**不得**更改块头版本字段中未被BIP YYYY(TODO)保留的任何位,也不得允许块头时间戳的递增速度快于挂钟时间。
  9. 希望包含大型coinbase交易的客户端可以向服务器发送一个ADDITIONAL_COINBASE_LENGTH消息:

  10. additional_length 字段不得考虑任何coinbase长度(根据上述规定,最多58个字节),常规支付输出(具有最多255字节scriptPubKey的单个输出),也不得考虑描述coinbase交易中输出数量的字节。

  11. 因此,即使客户端使用的额外长度超过指定的 additional_length 的328字节,工作提供者必须始终提供有效的工作(具有255字节scriptPubKey的输出总长度为266字节,加上58字节的coinbase数据,再加上表示coinbase交易中输出数量所需的最多4个额外字节)。

  12. 如果服务器没有收到ADDITIONAL_COINBASE_LENGTH消息,则服务器应该表现得好像它收到了一个 additional_length 设置为0的ADDITIONAL_COINBASE_LENGTH消息。

  13. 客户端应该首选不使用额外的coinbase交易长度。

  14. 客户端通过以下方式从BLOCK_TEMPLATE_HEADER构建候选标头:

    • 字段从相关消息字段复制到候选标头中,仅未提供nonce。
    • 客户端可以更改BIP YYYY(TODO:Drak的BIP)保留的块头版本字段位,并在生成工作时每秒将块头时间戳递增1。客户端不得更改块头版本字段中未被BIP YYYY(TODO)保留的任何位,也不得允许块头时间戳的递增速度快于挂钟时间。
    • 请注意,通过利用可用的版本位、标头nonce空间以及每秒递增一次标头时间,接收BLOCK_TEMPLATE_HEADER消息的客户端可以生成足够的工作量,以大约每秒完成70 TH,并且具有4个冲突的第一个压缩块(即通过保留2个版本位),而无需进一步的模板更新。
  15. 当客户端找到nonce的组合,导致块头哈希小于相应BLOCK_TEMPLATE/BLOCK_TEMPLATE_HEADER消息中的 target_hash 时,它们必须提交一个带有完整构建的coinbase交易(对于WINNING_NONCE)和nonce填充的WINNING_NONCE/WINNING_NONCE_HEADER消息。

    • user_tag 可以设置为任何内容,最大长度为255字节。它可以用于报告和统计收集目的以及跟踪性能。与消息的其余部分不同,user_tag 不得用于计算支付信息,因为它未经工作本身验证。
    • coinbase_tx 必须(显然,因为客户端没有它)在没有witness保留值(或coinbase交易txid中未包含的任何未来附加共识数据)的情况下进行编码。
  16. 需要正在处理的块的完整数据的客户端(例如,用于弱块中继到池以抽查此类工作的有效性),可以使用TRANSACTION_DATA_REQUEST消息请求它。

    • 接收到template_timestamp 与最近发送的BLOCK_TEMPLATE匹配的TRANSACTION_DATA_REQUEST消息的服务器,必须回复一个签名的TRANSACTION_DATA消息,该消息提供用于在BLOCK_TEMPLATE中构建 merkle_path 的完整交易集、previous_block 字段引用的块头以及验证块模板所需的任何其他附加数据(例如,witness保留值)。
    • 如果客户端没有及时收到响应TRANSACTION_DATA_REQUEST的TRANSACTION_DATA消息,则应该首选使用来自其他工作提供者提供的工作。
    • extra_block_datatransactions 中数据的编码被故意保留为未定义,并且此协议的非完全验证实现者不得以任何方式解释它们,只能将其解释为不透明的字节数组。
    • TRANSACTION_DATA_REQUEST发送者必须确保以向前和向后兼容的方式提供数据,以确保数据的最终接收者可以解释它,即使面对新的、共识可选的数据。这在升级期间允许在TRANSACTION_DATA生成和解释方面具有更大的灵活性,但代价是破坏了一些潜在的优化,这些优化将需要版本协商来提供对先前版本的支持。
    • 为了解决此限制,TRANSACTION_DATA消息中不透明数据的格式可以在分叉激活时以不兼容的方式更改,前提是从代码发布到激活有足够的时间(因为任何理智的分叉都必须有),并且在SHARE和BLOCK_TEMPLATE中都有对新分叉的支持信号(例如,对于使用BIP 9激活的软分叉)。
  17. 如果工作服务器需要将客户端迁移到新主机,则它可以发送一个NEW_WORK_SERVER消息,指示客户端应连接到哪里。

    • 客户端必须在对NEW_WORK_SERVER消息采取行动之前验证 signature,如果签名无效,则断开与工作提供者的连接并尝试重新连接(在原始主机/IP上)。
    • 接收到有效NEW_WORK_SERVER消息的客户端必须new_host_port 字段中存在的主机名/IP建立连接(编码为主机名_或_ip:端口),并且必须断开当前连接。
    • 无法连接到提供的主机的客户端必须仍然断开当前连接,并且应该定期重试连接到新主机(如果适用,则重试DNS解析),在此期间从备用工作服务器检索工作。
    • 客户端必须验证新主机上提供的PROTOCOL_VERSION public_key 是否与当前正在使用的密钥匹配。因此,NEW_WORK_SERVER不能用于迁移到新的身份验证密钥,并且不得重置TOFU状态。
  18. 实现者可以选择性地通过处理VENDOR_MESSAGE消息来支持此协议的扩展。

    • 如果客户端无法识别 vendor 字段中的值,则必须忽略该消息。
    • 如果 flags 字段中索引0处的位被设置,则客户端必须在对VENDOR_MESSAGE消息采取行动之前验证 signature,如果签名无效,则断开与工作提供者的连接并尝试重新连接。如果客户端无法识别 vendor 字段中的值,则可以选择性地跳过 signature 验证。
    • 如果 flags 字段中索引0处的位未设置,则必须省略 signature 字段。
    • vendor 字段必须唯一地描述构建操作规范的实体。作为例外,“stratum”可用于指示发送原始stratum命令,只要它们符合以下限制。
    • VENDOR_MESSAGE不得导致超出其他消息已允许范围的支付信息更改(即,如果客户端处于非最终工作模式,则任何VENDOR_MESSAGE都不得修改客户端正在使用的支付信息)。
    • 未签名的VENDOR_MESSAGE不得导致客户端连接的工作服务器的更改。
    • VENDOR_MESSAGE不得导致客户端操作的更改(例如,哈希率更改、客户端重新启动等),除非客户端处于最终工作模式,VENDOR_MESSAGE已签名,并且结果是临时的(例如远程重启客户端)。
    • 客户端响应VENDOR_MESSAGE所采取的任何进一步操作都未定义。

消息定义

Permalink: 消息定义

PROTOCOL_SUPPORT

Permalink: PROTOCOL_SUPPORT

字段名 类型 大小 编码 目的
message_type byte 1 字节 常量 1 消息类型
message_length uint32_t 3 字节 字节 {0x06, 0x00, 0x00} 消息的剩余长度,顺序为{低位字节,次低位字节,次高位字节},其中高位字节隐式为0
max_version uint16_t 2 字节 Little-Endian Integer 客户端支持的最大协议版本(目前必须为1)
min_version uint16_t 2 字节 Little-Endian Integer 客户端支持的最小协议版本(目前必须为1)
flags uint16_t 2 字节 16 个标志位 指示客户端支持的可选协议功能的标志(目前仅定义了0到3之间的值,包括0和3)
PROTOCOL_VERSION

Permalink: PROTOCOL_VERSION

字段名 类型 大小 编码 目的
message_type byte 1 字节 常量 2 消息类型
message_length uint32_t 3 字节 字节 {0x25, 0x00, 0x00} 消息的剩余长度,顺序为{低位字节,次低位字节,次高位字节},其中高位字节隐式为0
version uint16_t 2 字节 Little-Endian Integer 服务器选择使用的版本(目前始终为1)
flags uint16_t 2 字节 16 个标志位 指示服务器选择使用的可选协议功能的标志。
public_key secp256k1 Public Key 33 字节 “压缩”secp256k1公钥 将用于验证剩余消息的公钥
ADDITIONAL_COINBASE_LENGTH

Permalink: ADDITIONAL_COINBASE_LENGTH

字段名 类型 大小 编码 目的
message_type byte 1 字节 常量 3 消息类型
message_length uint32_t 3 字节 字节 {0x02, 0x00, 0x00} 消息的剩余长度,顺序为{低位字节,次低位字节,次高位字节},其中高位字节隐式为0
additional_length uint16_t 2 字节 Little-Endian Integer 需要为coinbase交易保留的额外大小,请参阅消息定义以了解更多信息。
BLOCK_TEMPLATE

Permalink: BLOCK_TEMPLATE

字段名 类型 大小 编码 目的
message_type byte 1 字节 常量 4 消息类型
message_length uint32_t 3 字节 Little-Endian Integer 消息的剩余长度,顺序为{低位字节,次低位字节,次高位字节},其中高位字节隐式为0
signature secp256k1 compact signature 64 字节 secp256k1 ECDSA签名,编码为R、S,均为大端字节序 SHA256(4 加上此消息中的所有剩余数据)上的签名
template_timestamp uint64_t 8 字节 Little-Endian Integer 生成此模板的时间戳,自1970年1月1日以来的毫秒数
target_hash uint256 32 字节 Little-Endian Integer 工作响应应匹配的目标哈希值(编码为小端字节序,块哈希应小于该值,当解释为小端字节序时)
default_header_version uint32_t 4 字节 Little-Endian Integer 块头中的默认版本字段
previous_block block hash 32 字节 标准双SHA256输出的块哈希 当前最佳块的块哈希(应在其上构建新块)
default_header_time uint32_t 4 字节 Little-Endian Integer 块头中的默认时间戳字段
header_nbits uint32_t 4 字节 Little-Endian Integer 块头中的“nBits”字段
merkle_path 32字节哈希数组 1 + N*32 字节 1个计数字节 + N个32字节的双SHA256哈希 到coinbase交易的Merkle路径
coinbase_tx_remaining_value uint64_t 8 字节 Little-Endian Integer 要分配给本地支付地址的剩余值
coinbase_tx_version uint32_t 4 字节 Little-Endian Integer 应在coinbase交易上设置的版本字段
coinbase_prefix byte array 1-97 字节 1个长度字节 + N个字节 应放置在coinbase交易中coinbase字段开头的数据
coinbase_postfix byte array 1-97 字节 1个长度字节 + N个字节 应放置在coinbase交易中coinbase字段末尾的数据
coinbase_tx_input_nSequence uint32_t 4 字节 Little-Endian Integer coinbase交易的输入的nSequence字段
coinbase_tx_remaining_data_len uint16_t 2 字节 Little-Endian Integer 剩余coinbase交易数据的长度(即输出的长度 + coinbase交易的锁定时间)
coinbase_tx_output_count Compact Size 1-5 字节 使用标准Bitcoin协议紧凑尺寸编码 要附加到coinbase交易末尾的输出数量
coinbase_tx_outputs_to_append Transaction Outputs N*(8 + P + M) 字节 compactsize lengthscriptPubKey) 应包含在coinbase交易的输出列表末尾的输出
coinbase_locktime uint32_t 4 字节 Little-Endian Integer coinbase交易的锁定时间字段
WINNING_NONCE

Permalink: WINNING_NONCE

字段名 类型 大小 编码 目的
message_type byte 1 字节 常量 5 消息类型
message_length uint32_t 3 字节 Little-Endian Integer 消息的剩余长度,顺序为{低位字节,次低位字节,次高位字节},其中高位字节隐式为0
template_timestamp uint64_t 8 字节 Little-Endian Integer 从用于生成此工作的BLOCK_TEMPLATE消息复制的模板时间戳字段
header_version uint32_t 4 字节 Little-Endian Integer 块头中的版本字段
header_timestamp uint32_t 4 字节 Little-Endian Integer 块头中的时间戳字段
header_nonce uint32_t 4 字节 Little-Endian Integer 块头中的nonce字段
user_tag bytes 1-256 字节 长度字节,后跟N个字节 可以填充的自由标签,用于统计目的
coinbase_tx_length uin32_t 4 字节 Little-Endian Integer coinbase交易的长度(以及此消息的其余部分)
coinbase_tx Transaction 47+ 字节 像任何其他Bitcoin交易一样 完全形成的编码的coinbase交易
TRANSACTION_DATA_REQUEST

Permalink: TRANSACTION_DATA_REQUEST

字段名 类型 大小 编码 目的
message_type byte 1 字节 常量 6 消息类型
message_length uint32_t 3 字节 字节 {0x08, 0x00, 0x00} 消息的剩余长度,顺序为{低位字节,次低位字节,次高位字节},其中高位字节隐式为0
template_timestamp uint64_t 8 字节 Little-Endian Integer 客户端需要完整交易的BLOCK_TEMPLATE消息的模板时间戳字段
TRANSACTION_DATA

Permalink: TRANSACTION_DATA

字段名 类型 大小 编码 目的
message_type byte 1 字节 常量 7 消息类型
message_length uint32_t 3 字节 Little-Endian Integer 消息的剩余长度,顺序为{低位字节,次低位字节,次高位字节},其中高位字节隐式为0
signature secp256k1 compact signature 64 字节 secp256k1 ECDSA签名,编码为R、S,均为大端字节序 SHA256(7 加上此消息中的所有剩余数据)上的签名
template_timestamp uint64_t 8 字节 Little-Endian Integer 服务器为其提供完整交易的TRANSACTION_DATA_REQUEST消息的模板时间戳字段
previous_header Block header 80 字节 序列化的Bitcoin块头 此工作基于的先前块的标头
extra_block_data bytes 4+ 字节 4字节小端长度,后跟额外数据 块验证可能需要的不透明二进制数据
tx_count uint32_t 4 字节 Little-Endian Integer 后续交易的数量(应该是候选块中的交易总数 - coinbase交易的1个)
transactions opaque binary data blobs 列表 N * (4 + tx len) 字节 4字节交易数据长度,后跟不透明的交易数据二进制blob,每个交易重复 交易本身
COINBASE_PREFIX_POSTFIX

Permalink: COINBASE_PREFIX_POSTFIX

字段名 类型 大小 编码 目的
message_type byte 1 字节 常量 8 消息类型
message_length uint32_t 3 字节 Little-Endian Integer 消息的剩余长度,顺序为{低位字节,次低位字节,次高位字节},其中高位字节隐式为0
signature secp256k1 compact signature 64 字节 secp256k1 ECDSA签名,编码为R、S,均为大端字节序 SHA256(8 加上此消息中的所有剩余数据)上的签名
message_timestamp uint64_t 8 字节 Little-Endian Integer 生成此消息的时间戳,自1970年1月1日以来的毫秒数
coinbase_prefix_postfix bytes 1-97 字节 1个字节长度,后跟N个字节 应添加到BLOCK_TEMPLATE中提供的coinbase前缀的后缀,在客户端添加任何其他数据推送之前
BLOCK_TEMPLATE_HEADER

Permalink: BLOCK_TEMPLATE_HEADER

字段名 类型 大小 编码 目的
message_type byte 1 字节 常量 9 消息类型
message_length uint32_t 3 字节 字节 {0xbc, 0x00, 0x00} 消息的剩余长度,顺序为{低位字节,次低位字节,次高位字节},其中高位字节隐式为0
signature secp256k1 compact signature 64 字节 secp256k1 ECDSA签名,编码为R、S,均为大端字节序 SHA256(9 加上此消息中的所有剩余数据)上的签名
template_timestamp uint64_t 8 字节 Little-Endian Integer 生成此模板的时间戳,自1970年1月1日以来的毫秒数
template_variant uint64_t 8 字节 Little-Endian Integer 一个唯一的ID,用于标识此BLOCK_TEMPLATE_HEADER,以包含在相应的WINNIN_NONCE_HEADER消息中
target_hash uint256 32 字节 Little-Endian Integer 工作响应应匹配的目标哈希值(编码为小端字节序,块哈希应小于该值,当解释为小端字节序时)
default_header_version uint32_t 4 字节 Little-Endian Integer 块头中的默认版本字段
previous_block block hash 32 字节 标准双SHA256输出的块哈希 当前最佳块的块哈希(应在其上构建新块)
merkle_root uint256 32 字节 双 SHA256 哈希 块头中的merkle根字段
default_header_time uint32_t 4 字节 Little-Endian Integer 块头中的默认时间戳字段
header_nbits uint32_t 4 字节 Little-Endian Integer 块头中的“nBits”字段
WINNING_NONCE_HEADER

Permalink: WINNING_NONCE_HEADER

字段名 类型 大小 编码 目的
message_type byte 1 字节 常量 10 消息类型
message_length uint32_t 3 字节 Little-Endian Integer 消息的剩余长度,顺序为{低位字节,次低位字节,次高位字节},其中高位字节隐式为0
template_timestamp uint64_t 8 字节 Little-Endian Integer 从用于生成此工作的BLOCK_TEMPLATE消息复制的模板时间戳字段
template_variant uint64_t 8 字节 Little-Endian Integer 对应的BLOCK_TEMPLATE_HEADER消息中的 template_variant
header_version uint32_t 4 字节 Little-Endian Integer 块头中的版本字段
header_timestamp uint32_t 4 字节 Little-Endian Integer 块头中的时间戳字段
header_nonce uint32_t 4 字节 Little-Endian Integer 块头中的nonce字段
user_tag bytes 1-256 字节 长度字节,后跟N个字节 可以填充的自由标签,用于统计目的
NEW_WORK_SERVER

Permalink: NEW_WORK_SERVER

字段名 类型 大小 编码 目的
message_type byte 1 字节 常量 11 消息类型
message_length uint32_t 3 字节 Little-Endian Integer 消息的剩余长度,顺序为{低位字节,次低位字节,次高位字节},其中高位字节隐式为0
signature secp256k1 compact signature 64 字节 secp256k1 ECDSA签名,编码为R、S,均为大端字节序 SHA256(11 加上此消息中的所有剩余数据)上的签名
new_host_port String 1 长度字节 + 最多 255 字节的字符串 字符串编码为长度字节,后跟 host:port 用于此工作提供程序的新连接主机
VENDOR_MESSAGE

Permalink: VENDOR_MESSAGE

字段名 类型 大小 编码 目的
message_type byte 1 字节 常量 12 消息类型
message_length uint32_t 3 字节 Little-Endian Integer 消息的剩余长度,顺序为{低位字节,次低位字节,次高位字节},其中高位字节隐式为0
flags uint16_t 1 byte1 8 个标志位 指示服务器选择使用的可选消息功能的标志。
signature secp256k1 compact signature 0 或 64 字节 secp256k1 ECDSA签名,编码为R、S,均为大端字节序 SHA256(12 加上此消息中的所有剩余数据)上的签名,仅当 flags 的位 0 为 1 时存在。
vendor String 1 长度字节 + 最多 255 字节的字符串 字符串编码为长度字节,后跟 vendor 消息的供应商描述符
message bytes N 字节,直至消息结尾 以供应商定义的方式编码的消息 供应商处理的消息本身

通过广播媒介的最终工作协议

Permalink: 通过广播媒介的最终工作协议

  1. 对于有内部带宽限制或工作服务器连接限制的矿场,支持使用广播媒介来发布工作更新和接收成功的 nonce。为了协商每个客户端的信息,客户端首先正常连接,然后接收广播更新。
  2. 客户端必须首先使用 TCP 连接,交换 PROTOCOL_SUPPORT/PROTOCOL_VERSION 消息,如上面的工作协议部分所定义。
    • 由于 BLOCK_TEMPLATE_HEADER 消息必然是每个客户端独有的,如果生成的 PROTOCOL_VERSION 消息表明是协议的 header 变体,客户端不得尝试协商广播更新机制。因此,希望协商广播更新机制的客户端不应表明支持工作协议的 header 变体。
    • 由于预计工作服务器将有多个关联的客户端,在接收到 COINBASE_PREFIX_POSTFIX 之前以及除非接收到,客户端不得尝试协商广播更新机制。 因此,如果没有提供 COINBASE_PREFIX_POSTFIX,客户端必须继续按照工作协议部分中的定义运行。
  3. 在从工作服务器接收到 COINBASE_PREFIX_POSTFIX 和初始 BLOCK_TEMPLATE 之后,客户端可以发送 VENDOR_MESSAGE,表明他们希望使用的广播机制类型。 这种协商和网络级别的注册被特意地保留为未定义,但是对于基于 UDP 的本地 IP 广播通信,可以使用以下协议:
    • 客户端发送一个包含 vendor "broadcast.udp" 和零长度 message 的 VENDOR_MESSAGE。
    • 服务器使用一个包含 vendor "broadcast.udp" 的 VENDOR_MESSAGE 进行响应,表明它愿意通过 UDP 广播提供未来的 BLOCK_TEMPLATE 消息,知道如何寻址到客户端的 UDP 数据包(例如,如果客户端是从本地子网上的 IPv4 地址连接的,则服务器知道将到达客户端的适当广播地址),以及一个 message,其中包含客户端应绑定的双字节 UDP 端口,后跟一个 4 字节的 magic value,用于标识工作更新数据包。
    • 客户端在用于出站 TCP 连接的同一接口上绑定到指定的 UDP 端口,断开 TCP 连接并等待通过 UDP 进行的未来更新。
    • 当服务器希望提供更新的 BLOCK_TEMPLATE 消息时,它使用与上述相同的编码,前缀为服务器的 VENDOR_MESSAGE 中提供的 4 字节 magic value,并广播它以确保每个注册的客户端都将收到它。
    • 在所需端口上接收 UDP 数据包的客户端必须验证数据包的前 4 个字节是否与服务器的 VENDOR_MESSAGE 中提供的 4 字节 magic value 匹配,并且 BLOCK_TEMPLATE 的 签名 是否正确,如上面的工作协议部分所述。 完成后,客户端必须切换到新提供的工作,如上面的工作协议部分所述。
    • 发现与工作目标匹配的 nonce 的客户端(如上面的工作协议部分所定义)必须生成适当的 WINNING_NONCE 消息,在其前面加上服务器的 VENDOR_MESSAGE 中指定的 magic value,并通过 UDP 将其发送到用于初始 TCP 连接的同一 IP 地址和端口组合上的工作服务器。
    • 向工作服务器发送 WINNING_NONCE 消息的客户端必须多次发送相同的 WINNING_NONCE 消息,以确保可靠的交付。
    • 这意味着接受 "broadcast.udp" VENDOR_MESSAGE 的服务器必须在具有相同 IP/端口的 UDP 和 TCP 套接字上绑定,并接收以它在 UDP 套接字上提供给客户端的 4 字节 magic value 为前缀的 WINNING_NONCE 消息。
    • 工作服务器必须假定客户端将不会收到其他每个 BLOCK_TEMPLATE 消息。 因此,对于具有新的 previous_block 字段的 BLOCK_TEMPLATE,工作服务器应该向每个客户端多次广播 BLOCK_TEMPLATE。 对于不包含新的 previous_block 字段的BLOCK_TEMPLATE,服务器可以复制广播或以比其他方式更快的速率提供新的 BLOCK_TEMPLATE。
  4. 使用广播机制的客户端不得尝试在广播套接字上使用除 WINNING_NONCE 之外的任何消息,并且不得期望在广播套接字上接收除 BLOCK_TEMPLATE 之外的任何消息。

Pool 协议规范

Permalink: Pool 协议规范

  1. 所有消息在线上都使用 1 字节的 message_type 前缀进行序列化,后跟 message_length(作为 3 字节整数,不包括 message_typemessage_length 字段),然后是消息本身。 除非另有说明,否则所有数字都以小端字节序编码。
  2. 节点不得在消息中发送任何多余的数据。 定义为具有恒定大小长度的消息必须使用指定的精确长度进行编码。
  3. 该协议以版本握手开始,"客户端"(即 payout-info-receiver)发送 PROTOCOL_SUPPORT 消息,而"服务器"(即 payout-info-provider)以 PROTOCOL_VERSION 进行响应。
  4. PROTOCOL_VERSION 消息包括一个 public_key,该 public_key 将用于签署从服务器发送到客户端的各种其他消息。
    • 客户端必须至少实现“首次使用信任”身份验证机制,并使用提供的 public_key 来验证来自同一 payout 信息提供者的任何剩余消息,即使跨断开/重新连接,也适用于一个会话。
    • 客户端可以允许用户指定预期的 public_key。 如果客户端允许这样做,则它应该允许用户通过输入 bech32-encoded-hash160-of-public-key@ip-or-host:port 格式的工作提供者来指定预期的 public_key(例如 [tb1qps9dq95rz7cramm0pjka0pd2tv8qrjyjj6y4me@1.1.1.1]():8888)。
    • 客户端应该提供 UI 暴露的 TOFU 状态重置机制(即重新连接并允许服务器提供任何公钥)。 客户端可以在 power-cyle 上重置 TOFU 状态(例如,仅在内存中存储 TOFU 状态而不将其持久化到非易失性存储中)。
    • 服务器必须将与 public_key 对应的私钥持久化到非易失性存储中,并持久地使用同一密钥。
    • 目前,PROTOCOL_SUPPORT 或 PROTOCOL_VERSION 中的 flags 中未定义任何位,客户端和服务器应该flags 设置为 0。
    • 接收到在 PROTOCOL_SUPPORT flags 中设置的未知位的服务器应该简单地忽略它们,并且不要将它们包含在响应的 PROTOCOL_VERSION flags 中。
  5. 在初始握手之后,客户端向服务器发送 USER_AUTH 消息,标识其自身并请求 PAYOUT_INFO 以及相应的 ACCEPT_USER_AUTH 和 SHARE_DIFFICULTY 消息。
    • 通过 USER_AUTH 消息成功验证身份不应使该用户能够执行除贡献于由 user_id 标识的用户的奖励之外的任何操作。 因此,user_auth 中的弱身份验证或无身份验证被认为是可接受的,但是矿池可以希望使用 user_auth 来要求客户端执行加密身份验证方案(例如,通过使用矿池的静态公钥和临时密钥执行 ECDH, 并使用结果来加密密码)。
    • 如果矿池需要身份验证,并且第一个 USER_AUTH 无法标识经过正确身份验证的用户,则服务器必须在收到 USER_AUTH 消息后立即断开客户端的连接。
    • 为了允许矿池代理在单个连接上多路复用多个用户,可以在单个连接上发送多个 USER_AUTH 消息。
    • 矿池代理不得在单个连接上多路复用多个用户,除非该代理正在生成自己的工作,并且不接受来自用户的不同工作。
    • 接收到 USER_AUTH 的服务器必须立即使用 ACCEPT_USER_AUTH 或 REJECT_USER_AUTH 以及与 USER_AUTH 中相同的 user_id 进行响应。
    • 如果矿池需要身份验证,并且第一个 USER_AUTH 之后的 USER_AUTH 无法标识经过正确身份验证的用户,则服务器必须使用 REJECT_USER_AUTH 消息进行响应。
    • 客户端不得发送具有 user_id 的 USER_AUTH,因为它已经接收到具有相同 user_id 的 ACCEPT_USER_AUTH,除非它首先发送了具有相同 user_id 的 DROP_USER 消息。
    • 客户端不得在每个 USER_AUTH/ACCEPT_USER_AUTH 请求/响应对中发送多个 DROP_USER 消息,其具有尚未通过接收 ACCEPT_USER_AUTH 成功注册的 user_id
    • 客户端不得为每个 USER_AUTH/ACCEPT_USER_AUTH 请求/响应对发送多个 DROP_USER 消息,其具有相同的 user_id
    • 服务器不得在收到 DROP_USER 消息后发送任何进一步的 ACCEPT_USER_AUTH/SHARE_DIFFICULTY 消息。 请注意,由于延迟,这可能会导致客户端在发送 DROP_USER 消息后的一小段时间内收到更多消息。
    • 服务器不得发送 REJECT_USER_AUTH 消息,除非是响应于它不会发送 ACCEPT_USER_AUTH 响应的 USER_AUTH 消息。
    • 类似地,服务器不得发送 ACCEPT_USER_AUTH 消息,以响应于它也会发送 REJECT_USER_AUTH 消息的 USER_AUTH 消息。 服务器不得发送具有从未包含在收到的 USER_AUTH 消息中的 user_id 的 ACCEPT_USER_AUTH 消息,但是如果它希望更改给定用户的每用户 payout 信息,则可以发送多个 ACCEPT_USER_AUTH 消息。
    • 具有多个以相同 user_id 连接的客户端的矿池代理必须将所有 ACCEPT_USER_AUTH 和 SHARE_DIFFICULTY 消息中继到具有相同 user_id 的所有用户。
    • 在第一个客户端连接后,矿池代理对 user_auth 的处理被特意地保留为未指定,从而允许代理决定允许所有 user_auth 值,将它们与先前成功的 user_auth 值进行比较,或实现他们希望的任何其他行为。
    • 用户可以suggested_target 设置为非最大 uint256 值,以表明它希望在其 SHARE_DIFFICULTY 消息中具有特定的 share_target。 不希望指示建议目标值的用户必须suggested_target 设置为全部为 1。
    • 用户应该minimum_target 设置为非最大 uint256 值,以表明它无法以比此目标所暗示的更快的速率提供 share。 用户几乎肯定应该minimum_target 的最高有效 4 个字节设置为 0,大致对应于 1 的“难度”。
  6. ACCEPT_USER_AUTH 消息可以从服务器发送到客户端,如上面一节所述。
    • 客户端必须在对 ACCEPT_USER_AUTH 消息采取行动之前验证其 签名,如果签名无效,则断开与矿池的连接并尝试重新连接。
    • 客户端必须验证 ACCEPT_USER_AUTH 中的 user_id 字段是否与他们发送的 USER_AUTH 的 user_id 字段匹配,以确保该工作支付到他们的矿池帐户中,否则断开与矿池的连接。
    • 客户端应该验证给定的 message_timestamp 是否在可接受的范围内(即接近现在)。
    • 客户端必须始终忽略任何 message_timestamp 低于客户端已在具有相同 user_id 的 ACCEPT_USER_AUTH 消息中看到的合理范围内的最高 message_timestamp 的 ACCEPT_USER_AUTH 消息。
    • 服务器不得在同一连接上发送两个具有不同大小的 coinbase_postfix 的 ACCEPT_USER_AUTH 消息。 服务器可以断开客户端的连接以更改 coinbase_postfix 的大小,从而迫使客户端重新验证所有已连接的用户,但是应该尽可能避免这样做。 此要求可以简化代理服务器的实现。
    • coinbase_postfix 必须明确地将用户标识到矿池,从而使他们能够标识 SHARE 的来源并将其验证给用户。
    • 非代理服务器不得包含超过 42 字节的 coinbase_postfix(不包括长度字节),并且代理服务器不得coinbase_postfix 添加超过 8 个字节。 这必然不允许在原始矿池服务器和任何客户端之间存在多个代理。
  7. 在使用 USER_AUTH/ACCEPT_USER_AUTH 成功验证身份后,必须从服务器向客户端发送初始的 SHARE_DIFFICULTY 消息,并且服务器可以发送其他 SHARE_DIFFICULTY 消息,以将 SHARE 和 WEAK_BLOCK 消息的量限制为合理的速率。
    • 客户端必须在对 SHARE_DIFFICULTY 消息采取行动之前验证其 签名,如果签名无效,则断开与矿池的连接并尝试重新连接。
    • 客户端应该验证给定的 message_timestamp 是否在可接受的范围内(即接近现在)。
    • 客户端必须始终忽略 message_timestamp 低于客户端已在 SHARE_DIFFICULTY 消息中看到的合理范围内的最高 message_timestamp 的 SHARE_DIFFICULTY 消息。
    • 发现符合 share_target 的工作的客户端必须发送如下所述的 SHARE 消息。
    • 发现符合 weak_block_target 的工作的客户端必须发送如下所述的 WEAK_BLOCK 消息。
    • 发现符合当前 weak_block_targetshare_target 的有效 SHARE 的客户端必须提交 SHARE 和 WEAK_BLOCK 消息。
    • 服务器不得发送 share_targetweak_block_target 设置为高于 USER_AUTH 消息中为相应 user_id 提供的 minimum_target 的数字的 SHARE_DIFFICULTY。
    • 服务器在选择 share_targetweak_block_target 值时应该考虑客户端的 suggested_target
  8. 在初始版本握手之后,以及在客户端挖矿之前,必须从服务器向客户端发送初始的 PAYOUT_INFO 消息。
    • 客户端必须在对 PAYOUT_INFO 消息采取行动之前验证其 签名,如果签名无效,则断开与矿池的连接并尝试重新连接。
    • 客户端应该验证给定的 message_timestamp 是否在可接受的范围内(即接近现在)。
    • 客户端必须始终忽略任何 message_timestamp 低于客户端已在 PAYOUT_INFO 消息中看到的合理范围内的最高 message_timestamp 的 PAYOUT_INFO 消息。
    • 矿池必须确保任何发送的(ACCEPT_USER_AUTH coinbase_postfix、PAYOUT_INFO remaining_payout_script、PAYOUT_INFO appended_outputs)元组在全局上是唯一的,并且不得在两个不同的连接中或对于不同的 user_id 发送相同的此类元组。
    • 矿池服务器应该appended_outputs_count 设置为 0。这使客户端可以为生成的 work size 具有一个简单的默认值,该默认值在各个矿池中是一致的。 具体来说,这会将矿池服务器提供的额外 coinbase 交易开销限制为单个 payout 输出,其最大 scriptPubKey 长度为 255 加上最多 50 个字节的 coinbase 数据。
    • 仍然,客户端必须实现对 appended_outputs_count 不为 0 的 PAYOUT_INFO 消息的处理,尽管他们可以选择首选具有较小 PAYOUT_INFO 的矿池,以避免需要工作服务器 ADDITIONAL_COINBASE_LENGTH 消息。
    • 矿池服务器不得appended_outputs_count 设置为高于 250,并且不得appended_outputs 中包含长度超过 252 的脚本。 因此,所有附加输出的总长度(包括 remaining_payout_script 值)不能超过 2^16 个字节。
  9. 在发现符合当前 share_target 的 nonce 集后,客户端必须构造一个 SHARE 消息并将其转发到服务器。
    • 服务器必须验证 coinbase_tx 是否具有以提供给用户的 coinbase_postfix 结尾的 coinbase 字段。 服务器不得基于 coinbase_postfix 标识以外的任何内容来识别 payout 信息。
    • coinbase_tx 中的第一个输出中的支付对象必须是最近的 PAYOUT_INFO 的 remaining_payout_script,该 remaining_payout_script 必须已在接收到 ACCEPT_USER_AUTH 消息的同一连接上接收,该 ACCEPT_USER_AUTH 消息的 coinbase_postfix 用于生成 share。
    • coinbase_tx 的下一个输出必须是包含在同一 PAYOUT_INFO 的 appended_outputs 中的输出,后跟客户端希望出于非支付目的而添加的任何输出。
    • coinbase_tx 必须在没有见证保留值的情况下进行编码(或 coinbase 交易 txid 中未包含的任何将来的附加共识数据)。
    • 请注意,由于 appended_outputs scriptPubKey 长度最多限制为 252 个字节,因此简化的客户端可以将输出作为字节字符串附加,而不是解析它们。
    • 客户端添加的任何输出(第一个输出除外)必须具有 0 值。
    • user_tag_1user_tag_2 可以设置为任何值,最大长度为 255 个字节。 它可以用于报告和统计信息收集目的以及跟踪性能。 user_tag_1user_tag_2 不得用于 payout 信息的计算中,因为它与 SHARE 消息的其余部分不同,没有通过 work 本身进行身份验证。
    • 用户可以user_tag_1 设置为唯一标识生成 share 的设备的值,并将 user_tag_2 设置为标识 share 本身的值,从而可以在 SHARE 和 SHARE_ACCEPTED/SHARE_REJECTED 消息之间建立关联。
    • 矿池服务器应该接受具有 previous_block 字段的 SHARE,该字段与矿池认为的 not-invalid 的任何区块匹配,该区块具有与矿池已验证的 total-work 最多的区块相同或更多的 total work(即,矿池应该接受基于他们认为不在最佳链上的区块构建的 SHARE,只要它们具有与其当前完全验证的提示相同或更多的 total work,即使他们仅 验证/接收了基于其构建的 block header,但是矿池不应该接受基于他们检查并发现无效的区块构建的 SHARE)。 这意味着矿池服务器应该接受基于区块 A 的 SHARE,直到具有更高 total-work 的区块已被完全验证,即使具有更高 total-work 的 header 已被 header 验证。
    • 为了确保此类 header 在矿池中可用,客户端可以包括其工作所基于的 block header。 客户端应该在他们提供给矿池的每个新 block header 的第一个 SHARE 中包含该 header,此后不应该包含它。 但是,服务器应该处理客户端在他们可以省略 previous_header 时或在他们应该包含 previous_header 时包含它的情况,并根据他们拥有的任何其他知识接受或拒绝该 share。
  • 为了减少通过不可靠连接拒绝的 share,客户端应该在重新连接后将任何丢失的 SHARE 重新传输到矿池,但是服务器不需要接受这些 share。 如果出于效率考虑而需要,服务器可以依赖客户端的 SHARE 消息的 coinbase_tx 使用来自在同一连接上发送的 ACCEPT_USER_AUTH 消息的 coinbase_postfix,但是,应尽一切努力允许使用最近关闭的连接的 ACCEPT_USER_AUTH 构建的在新连接上的提交。
  1. 在发现符合当前 weak_block_target 的 nonce 集后,客户端必须构造一个 WEAK_BLOCK 消息并将其转发到服务器。
    • WEAK_BLOCK 消息是包含在区块中的一组经过差分编码的交易,与连接上的先前 WEAK_BLOCK(而不是每个用户)进行比较编码。 但是,由于代理服务器不得允许用户生成 work,因此服务器可以期望 WEAK_BLOCK 消息包含有效的交易集(即,表示可能具有过时的 previous block hash 或错过 work 目标的 share,但在其他方面有效的 share)。
    • 除了 header、user_tag_1user_tag_2 字段(应以与 SHARE 消息相同的方式解释)之外,WEAK_BLOCK 消息还包含 txn_list 字段中的交易列表。
    • 为了读取 txn_list 字段,服务器会对其进行迭代,一次读取两个字节,这两个字节指示所选交易在连接上先前 WEAK_BLOCK 中的位置(从 0 开始索引,包括 coinbase 交易)。 值为 0 表示将提供原始交易,接下来的 4 个字节包含一个指示交易长度的小端整数,接下来的 N 个字节包含交易本身。 由于始终必须重新发送 coinbase 交易,因此 txn_list 中的前两个字节应始终为 0,接下来的 4 个字节为 coinbase 交易长度。
    • txn_list 中的第一个交易(coinbase 交易)必须coinbase_tx 在 SHARE 消息中出现的方式进行编码(即没有见证保留值)。 因此,完全验证区块所需的任何其他数据(否则会出现在 coinbase 交易中)(例如,见证保留值)必须extra_block_data 字段中发送。
    • 客户端必须在 WEAK_BLOCK 消息中包含完全验证候选区块所需的所有数据,但是,在第一个交易之后,交易本身以及 extra_block_data 字段的编码被特意地保留为未定义。 因此,非完全验证流程在第一个交易之后,不得将交易数据或 extra_block_data 解释为除不透明字节数组之外的任何内容。
    • 在工作协议中对 TRANSACTION_DATA 提供者的要求也适用于提供 WEAK_BLOCK 数据的客户端。
    • 服务器可以使用 WEAK_BLOCK 消息来抽查客户端正在完成的 work 的有效性,但是服务器必须接受基于任何先前区块的 WEAK_BLOCK,该先前区块具有与服务器的最佳已知有效区块相同的 total work。
  2. 收到 SHARE 或 WEAK_BLOCK 消息后,矿池服务器必须使用 SHARE_ACCEPTED 或 SHARE_REJECTED 消息进行响应。
    • user_tag_1user_tag_2 字段必须设置为 SHARE/WEAK_BLOCK 消息中提供的值。
    • 发送 SHARE_ACCEPTED 消息的矿池服务器必须根据矿池的 payout 方案,将 share 的价值记入用户的帐户。
    • SHARE_REJECTED 中的 reason 字段必须携带以下值之一,尽管可能会在此 BIP 的未来版本中定义更多值:
名称 含义
1 STALE_PREVBLOCK SHARE/WEAK_BLOCK 基于的先前区块与矿池知道的最高有效 total work 区块的 total work 不相同(或者矿池尚未收到给定的先前 block header)。
2 BAD_HASH header 未哈希到足够低的目标,以满足当前的 share_targetweak_block_target
3 DUPLICATE 给定的 work 已经提交(请注意,对于已发送等效 SHARE 的 WEAK_BLOCK,矿池不得发送 REJECT_SHARE 消息)
4 BAD_PAYOUT_INFO 给定的 SHARE/WEAK_BLOCK 未正确使用提供的 PAYOUT_INFO 和 ACCEPT_USER_AUTH
5 BAD_WORK 给定的 SHARE/WEAK_BLOCK 由于某些其他原因而无效,最可能是 WEAK_BLOCK 未通过有效性检查。
  1. 如果矿池服务器需要将客户端迁移到新主机,则它可以发送 NEW_POOL_SERVER 消息,指示客户端应连接到的位置。
    • 客户端必须在对 NEW_POOL_SERVER 消息采取行动之前验证其 签名,如果签名无效,则断开矿池服务器的连接并尝试重新连接(在原始主机/IP 上)。
    • 接收到有效的 NEW_POOL_SERVER 消息的客户端必须new_host_port 字段中存在的主机名/IP 建立连接(编码为 hostname_or_ip:port),并且必须断开当前连接。
    • 无法连接到提供的主机的客户端仍然必须断开当前连接,并且应该有规律地重试以连接到新主机(如果适用,重试 DNS 解析),同时从备用矿池服务器检索 payout 信息。
    • 客户端必须验证在新主机上提供的 PROTOCOL_VERSION public_key 是否与当前正在使用的公钥匹配。 因此,NEW_POOL_SERVER 不能用于迁移到新的身份验证密钥,并且不得重置 TOFU 状态。
  2. 实施者可以选择通过处理 VENDOR_MESSAGE 消息来支持此协议的扩展。
    • 如果客户端无法识别 vendor 字段中的值,则必须忽略该消息。
    • 如果设置了 flags 字段中索引为 0 的位,则客户端必须在对 VENDOR_MESSAGE 消息采取行动之前验证其 签名,如果签名无效,则断开矿池服务器的连接并尝试重新连接。 如果客户端无法识别 vendor 字段中的值,则可以选择跳过 signature 验证。
    • 如果 flags 字段中索引为 0 的位未设置,则必须省略 signature 字段。
    • vendor 字段必须唯一地描述构造操作规范的实体。 作为一个例外,“stratum”可以用于指示发送原始 stratum 命令,只要它们符合以下限制。
    • 未签名的 VENDOR_MESSAGE不得导致 payout 信息的更改。
    • 未签名的 VENDOR_MESSAGE不得导致客户端连接到的矿池服务器的更改。
    • VENDOR_MESSAGE不得导致客户端操作的更改(例如,哈希率更改、客户端重新启动等)。
    • 客户端响应于 VENDOR_MESSAGE 而采取的任何进一步操作都未定义。

消息定义

Permalink: 消息定义

PROTOCOL_SUPPORT

Permalink: PROTOCOL_SUPPORT

字段名称 类型 大小 编码 目的
message_type 字节 1 字节 常数 1 消息类型
message_length uint32_t 3 字节 字节 {0x06, 0x00, 0x00} 消息的剩余长度,顺序为 {低位字节、次低位字节、倒数第二高位字节},高位字节隐式为 0
max_version uint16_t 2 字节 小端整数 客户端支持的最高协议版本(当前必须为 1)
min_version uint16_t 2 字节 小端整数 客户端支持的最低协议版本(当前必须为 1)
flags uint16_t 2 字节 16 个标志位 指示客户端支持的可选协议功能的标志
PROTOCOL_VERSION

Permalink: PROTOCOL_VERSION

字段名称 类型 大小 编码 目的
message_type 字节 1 字节 常数 2 消息类型
message_length uint32_t 3 字节 字节 {0x25, 0x00, 0x00} 消息的剩余长度,顺序为 {低位字节、次低位字节、倒数第二高位字节},高位字节隐式为 0
version uint16_t 2 字节 小端整数 服务器已选择使用的版本(目前始终为 1)
flags uint16_t 2 字节 16 个标志位 指示服务器选择使用的可选协议功能的标志。
public_key secp256k1 公钥 33 字节 “压缩” secp256k1 公钥 将用于验证剩余消息的公钥
PAYOUT_INFO
Permalink: PAYOUT_INFO
字段名 类型 大小 编码 目的
message_type byte 1 字节 常数 13 消息类型
message_length uint32_t 3 字节 Little-Endian Integer(小端整数) 消息的剩余长度,顺序为 {最低有效字节,次低有效字节,次高有效字节},最高有效字节隐式为 0
signature secp256k1 compact signature(secp256k1 紧凑签名) 64 字节 secp256k1 ECDSA signature(secp256k1 ECDSA 签名)编码为 R, S,均为 big endian(大端) SHA256(13 后面跟此消息中的所有剩余数据) 上的签名
message_timestamp uint64_t 8 字节 Little-Endian Integer(小端整数) 生成此消息的时间戳,自 1970 年 1 月 1 日以来的毫秒数
remaining_payout_script Script(脚本) 1-256 字节 1 个长度字节,后跟 N 个字节的 script(脚本) 应该接收 coinbase 交易奖励的所有剩余值的 scriptPubKey
appended_outputs_count uint8_t 1 字节 Integer(整数) 应该在 coinbase 交易中的 self 和 remaining payout outputs 之后出现的 output(输出)的数量(最多 250 个)
appended_outputs Transaction Outputs(交易输出) N*(8 + 1 + M) 字节 1 字节 scriptPubKey(脚本公钥)长度,最多 252scriptPubKey) output(输出)本身
USER_AUTH

Permalink: USER_AUTH

字段名 类型 大小 编码 目的
message_type byte 1 字节 常数 14 消息类型
message_length uint32_t 3 字节 Little-Endian Integer(小端整数) 消息的剩余长度,顺序为 {最低有效字节,次低有效字节,次高有效字节},最高有效字节隐式为 0
suggested_target uint256 32 字节 Little-Endian Integer(小端整数) 用户建议的 share_target
minimum_target uint256 32 字节 Little-Endian Integer(小端整数) 用户支持的最小 share_target
user_id String(字符串) 1-256 字节 1 字节长度,后跟最多 255 字节的字符 用户的标识字符串
user_auth String(字符串) 1-256 字节 1 字节长度,后跟最多 255 字节的字符 用户必须提供的任何其他数据以验证身份。
ACCEPT_USER_AUTH

Permalink: ACCEPT_USER_AUTH

字段名 类型 大小 编码 目的
message_type byte 1 字节 常数 15 消息类型
message_length uint32_t 3 字节 Little-Endian Integer(小端整数) 消息的剩余长度,顺序为 {最低有效字节,次低有效字节,次高有效字节},最高有效字节隐式为 0
signature secp256k1 compact signature(secp256k1 紧凑签名) 64 字节 secp256k1 ECDSA signature(secp256k1 ECDSA 签名)编码为 R, S,均为 big endian(大端) SHA256(15 后面跟此消息中的所有剩余数据) 上的签名
user_id String(字符串) 1-256 字节 1 字节长度,后跟最多 255 字节的字符 用户的标识字符串
message_timestamp uint64_t 8 字节 Little-Endian Integer(小端整数) 生成此消息的时间戳,自 1970 年 1 月 1 日以来的毫秒数
coinbase_postfix bytes(字节) 1-51 字节 长度字节,后跟 N 个字节 必须出现在 coinbase 字段末尾的数据
REJECT_USER_AUTH

Permalink: REJECT_USER_AUTH

字段名 类型 大小 编码 目的
message_type byte 1 字节 常数 16 消息类型
message_length uint32_t 3 字节 Little-Endian Integer(小端整数) 消息的剩余长度,顺序为 {最低有效字节,次低有效字节,次高有效字节},最高有效字节隐式为 0
user_id String(字符串) 1-256 字节 1 字节长度,后跟最多 255 字节的字符 用户的标识字符串
DROP_USER

Permalink: DROP_USER

字段名 类型 大小 编码 目的
message_type byte 1 字节 常数 17 消息类型
message_length uint32_t 3 字节 Little-Endian Integer(小端整数) 消息的剩余长度,顺序为 {最低有效字节,次低有效字节,次高有效字节},最高有效字节隐式为 0
user_id String(字符串) 1-256 字节 1 字节长度,后跟最多 255 字节的字符 用户的标识字符串
SHARE_DIFFICULTY

Permalink: SHARE_DIFFICULTY

字段名 类型 大小 编码 目的
message_type byte 1 字节 常数 18 消息类型
message_length uint32_t 3 字节 Little-Endian Integer(小端整数) 消息的剩余长度,顺序为 {最低有效字节,次低有效字节,次高有效字节},最高有效字节隐式为 0
user_id String(字符串) 1-256 字节 1 字节长度,后跟最多 255 字节的字符 应该更新其 difficulty(难度)的用户的用户标识字符串
message_timestamp uint64_t 8 字节 Little-Endian Integer(小端整数) 生成此消息的时间戳,自 1970 年 1 月 1 日以来的毫秒数
share_target uint256 32 字节 Little-Endian Integer(小端整数) 用于与 share(份额)的 block hash(区块哈希)进行比较的 share target
weak_block_target uint256 32 字节 Little-Endian Integer(小端整数) 用于与必须提交的 share(份额)的 block hash(区块哈希)进行比较的 target
SHARE

Permalink: SHARE

字段名 类型 大小 编码 目的
message_type byte 1 字节 常数 19 消息类型
message_length uint32_t 3 字节 Little-Endian Integer(小端整数) 消息的剩余长度,顺序为 {最低有效字节,次低有效字节,次高有效字节},最高有效字节隐式为 0
header_version uint32_t 4 字节 Little-Endian Integer(小端整数) 区块头中的 version 字段
previous_block block hash(区块哈希) 32 字节 Block Hash(区块哈希)作为标准 double-SHA256(双 SHA256) output(输出) 构建此 share(份额)的先前区块的 block hash(区块哈希)
header_timestamp uint32_t 4 字节 Little-Endian Integer(小端整数) 区块头中的 timestamp 字段
header_nbits uint32_t 4 字节 Little-Endian Integer(小端整数) 区块头中的 "nBits" 字段
header_nonce uint32_t 4 字节 Little-Endian Integer(小端整数) 区块头中的 nonce 字段
merkle_path array of 32-byte hashes(32 字节哈希数组) 1 + N*32 字节 1 个计数字节 + N 个 32 字节 double-SHA256(双 SHA256)哈希 指向 coinbase 交易的 Merkle 路径
coinbase_tx_length uin32_t 4 字节 Little-Endian Integer(小端整数) coinbase 交易的长度
coinbase_tx Transaction(交易) 47+ 字节 像任何其他 Bitcoin 交易 完全形成的编码 coinbase 交易
user_tag_1 bytes(字节) 1-256 字节 长度字节,后跟 N 个字节 可以填充以用于统计目的的自由标签
user_tag_2 bytes(字节) 1-256 字节 长度字节,后跟 N 个字节 可以填充以用于统计目的的自由标签
previous_header Block header(区块头) 0 或 80 字节 序列化的 Bitcoin Block Header(比特币区块头) 此 work(工作)所基于的先前区块的头(仅在新时包含)
WEAK_BLOCK

Permalink: WEAK_BLOCK

字段名 类型 大小 编码 目的
message_type byte 1 字节 常数 20 消息类型
message_length uint32_t 3 字节 Little-Endian Integer(小端整数) 消息的剩余长度,顺序为 {最低有效字节,次低有效字节,次高有效字节},最高有效字节隐式为 0
header_version uint32_t 4 字节 Little-Endian Integer(小端整数) 区块头中的 version 字段
previous_block block hash(区块哈希) 32 字节 Block Hash(区块哈希)作为标准 double-SHA256(双 SHA256) output(输出) 构建此 share(份额)的先前区块的 block hash(区块哈希)
header_timestamp uint32_t 4 字节 Little-Endian Integer(小端整数) 区块头中的 timestamp 字段
header_nbits uint32_t 4 字节 Little-Endian Integer(小端整数) 区块头中的 "nBits" 字段
header_nonce uint32_t 4 字节 Little-Endian Integer(小端整数) 区块头中的 nonce 字段
merkle_path array of 32-byte hashes(32 字节哈希数组) 1 + N*32 字节 1 个计数字节 + N 个 32 字节 double-SHA256(双 SHA256)哈希 指向 coinbase 交易的 Merkle 路径
user_tag_1 bytes(字节) 1-256 字节 长度字节,后跟 N 个字节 可以填充以用于统计目的的自由标签
user_tag_2 bytes(字节) 1-256 字节 长度字节,后跟 N 个字节 可以填充以用于统计目的的自由标签
extra_block_data bytes(字节) 4+ 字节 4 字节 Little-Endian(小端)长度,后跟额外数据 块验证可能需要的 Opaque(不透明)二进制数据
txn_count uint32_t 4 字节 Little-Endian Integer(小端整数) 此块中的交易数量(如下)
txn_list transaction pointer list(交易指针列表) N 字节 指向上一个 WEAK_BLOCK 中的交易的 2 字节指针,或 0 表示完整交易 此块中包含的交易
WEAK_BLOCK_STATE_RESET

Permalink: WEAK_BLOCK_STATE_RESET

字段名 类型 大小 编码 目的
message_type byte 1 字节 常数 21 消息类型
message_length uint32_t 3 字节 字节 {0x00, 0x00, 0x00} 消息的剩余长度,顺序为 {最低有效字节,次低有效字节,次高有效字节},最高有效字节隐式为 0
SHARE_ACCEPTED

Permalink: SHARE_ACCEPTED

字段名 类型 大小 编码 目的
message_type byte 1 字节 常数 22 消息类型
message_length uint32_t 3 字节 Little-Endian Integer(小端整数) 消息的剩余长度,顺序为 {最低有效字节,次低有效字节,次高有效字节},最高有效字节隐式为 0
user_tag_1 bytes(字节) 1-256 字节 长度字节,后跟 N 个字节 相应 SHARE 或 WEAK_BLOCK 消息中提供的 user_tag_1
user_tag_2 bytes(字节) 1-256 字节 长度字节,后跟 N 个字节 相应 SHARE 或 WEAK_BLOCK 消息中提供的 user_tag_2
SHARE_REJECTED

Permalink: SHARE_REJECTED

字段名 类型 大小 编码 目的
message_type byte 1 字节 常数 23 消息类型
message_length uint32_t 3 字节 Little-Endian Integer(小端整数) 消息的剩余长度,顺序为 {最低有效字节,次低有效字节,次高有效字节},最高有效字节隐式为 0
reason uint8_t 1 字节 从可用原因中选择的值 原因指示器。 有关已定义原因的列表,请参见消息处理说明
user_tag_1 bytes(字节) 1-256 字节 长度字节,后跟 N 个字节 相应 SHARE 或 WEAK_BLOCK 消息中提供的 user_tag_1
user_tag_2 bytes(字节) 1-256 字节 长度字节,后跟 N 个字节 相应 SHARE 或 WEAK_BLOCK 消息中提供的 user_tag_2
NEW_POOL_SERVER

Permalink: NEW_POOL_SERVER

字段名 类型 大小 编码 目的
message_type byte 1 字节 常数 11 消息类型
message_length uint32_t 3 字节 Little-Endian Integer(小端整数) 消息的剩余长度,顺序为 {最低有效字节,次低有效字节,次高有效字节},最高有效字节隐式为 0
signature secp256k1 compact signature(secp256k1 紧凑签名) 64 字节 secp256k1 ECDSA signature(secp256k1 ECDSA 签名)编码为 R, S,均为 big endian(大端) SHA256(11 后面跟此消息中的所有剩余数据) 上的签名
new_host_port String(字符串) 1 长度字节 + 最多 255 字节的字符串 编码为长度字节,后跟 host:port 的字符串 要连接到此池的新主机
VENDOR_MESSAGE

Permalink: VENDOR_MESSAGE

字段名 类型 大小 编码 目的
message_type byte 1 字节 常数 12 消息类型
message_length uint32_t 3 字节 Little-Endian Integer(小端整数) 消息的剩余长度,顺序为 {最低有效字节,次低有效字节,次高有效字节},最高有效字节隐式为 0
flags uint16_t 1 byte1 8 flag bits(8 个标志位) 指示服务器选择使用的可选消息功能的标志。
signature secp256k1 compact signature(secp256k1 紧凑签名) 0 或 64 字节 secp256k1 ECDSA signature(secp256k1 ECDSA 签名)编码为 R, S,均为 big endian(大端) SHA256(12 后面跟此消息中的所有剩余数据) 上的签名,仅当 flags 的 bit 0 为 1 时才存在。
vendor String(字符串) 1 长度字节 + 最多 255 字节的字符串 编码为长度字节的字符串,后跟 vendor 消息的 Vendor 描述符
message bytes(字节) N 字节,直到消息结尾 以 Vendor 定义的方式编码的消息 Vendor 处理的消息本身

Discussion

Permalink: Discussion

为什么使用 TCP? UDP 不是更适合低延迟中继吗?因为时间敏感数据包被设计为适合 1 个 TCP 帧,所以使用 TCP 可以显著降低可靠传输和 NAT 穿越的复杂性,同时仍提供低延迟交付。 对于使用广播介质减少带宽,显然 TCP 不适用,但是通过未拥塞的 LAN 和冗余数据包应该可以轻松完成可靠的交付。 具有严重数据包丢失问题的用户应考虑使用更本地的池服务器,并通过 FEC 生成代理(例如 QUIC)进行连接,尽管为了降低复杂性,本规范中有意将此类协议的使用保留为未定义。为什么增加 weak blocks(弱块)中继的复杂性?由于基于 PPS 的池已成为出于商业原因的常见做法,因此某些池非常关心能够优化支付给他们的块的中继。 因此,为了避免池严重依赖其客户端来执行自己的仔细优化,可以使客户端有效地将部分块中继到池,从而进一步允许池抽查客户端正在哈希处理的工作的有效性。 不需要基于 weak-block(弱块)的中继的池可以选择简单地将 weak_block_difficulty 设置为当前的块难度,并在每个 WEAK_BLOCK 之后发送 WEAK_BLOCK_STATE_RESET 消息,这意味着客户端几乎没有机会中继压缩的弱块。对于当今的矿工,预期的 UX 差异是什么?这在很大程度上取决于挖掘硬件打算支持的复杂程度。 对于同时支持两者的硬件,矿工现在可以有两组主机字段,而不是当前的配置,其中将挖掘固件定向到连接到一个或多个池以从其获取 work(工作)和 payout(支付)信息,一个用于 work(工作),一个用于池。 对于更简单的挖掘固件,他们可以选择仅支持 work(工作)提供商,这些提供商可以指向一个代理,该代理将来自 work(工作)提供商的 work(工作)与来自池的 payout(支付)信息合并到 BLOCK_TEMPLATE 的一个流中。 此类代理服务器的示例位于作者的 GitHub上,该 GitHub 还支持充当现有硬件连接到的 stratum 服务器。难道许多矿工不太可能简单地选择连接到同一运营商以获取 work(工作)和池 payout(支付)信息吗?实际上,这是可能的,但是降低矿工获取 work(工作)信息的转换成本相对于当今的设置而言已经是一个显着优势。 此外,将协议分为两部分可以大大简化池的操作 - 允许池运营商简单地将 Bitcoin Core 用作 work(工作)服务器可以简化构建池服务器的工作。没有可靠时间源的挖掘设备呢?请注意,尽管时间戳在协议中使用,但是客户端可以在完全不知道当前时间的情况下完全兼容。 尽管服务器必须提供它,但是如果所有下游客户端仅将 timestamp(时间戳)字段用作不断增加的 ID,则它们可以正常运行(尽管通常应避免这样做,以免可能生成永远无法覆盖的更新)。为什么某些消息已签名而另一些消息未签名?通常,重复的每个客户端消息都保持未签名状态,以确保在池和 work(工作)服务器上的低开销。 假设无论考虑什么协议功能,攻击者都能够阻止所有 share(份额)到达任何池/work(工作)服务器,强制用户退回到辅助配置的池/work(工作)服务器,并了解用户的算力和行为,因此没有努力提供针对此类攻击的安全性。 相反,仅针对以下攻击提供安全性:攻击者能够将已经在线的算力重定向到新的池/payout(支付)信息/work(工作)。 值得注意的是,SHARE_ACCEPTED/SHARE_REJECTED 消息未签名,从而允许攻击者通过删除 share(份额)来默默地降低用户的算力,同时通知用户它们已被接受,但是 MITM 攻击者即使在签名的 SHARE_ACCEPTED 消息的情况下也可以这样做,只是检测速度略快,而不是只能在事后通过协调份额计数来完成。 此外,REJECT_USER_AUTH/DROP 用户消息未签名,因为它们的行为方式与攻击者可以简单地删除与该用户关联的消息和/或重置 TCP 连接的方式非常相似。为什么 WEAK_BLOCK 消息是 per-connection(按连接)而不是 per-user(按用户),以及为什么池代理不能接受客户端生成的工作?这使池服务器的实现更加轻巧和简单。 如果允许代理服务器为多个生成 work(工作)的客户端提供服务,则它们必须按原样转发 WEAK_BLOCK 消息,以避免客户端彼此干扰 weak blocks(弱块)的效率,从而使池服务器复杂化并增加其资源使用量。 鉴于此类代理服务器的唯一重要用例是向后兼容的池运营 stratum 服务器,因此启用此类用例几乎没有优势。

Acknowledgments

Permalink: Acknowledgments

感谢(按姓氏字母顺序排列)Jan Capek、Ivy Evans、James Hilliard、Greg Maxwell、Pavel Moravec 和 Alex Petrov 进行了多轮审查和反馈。 同时也感谢 Jonathan Cross、GitHub 上的 erikarvstedt、Jonas Nick、Jimmy Song 和其他一些人为副本编辑和文本建议提供的帮助。

  • 原文链接: github.com/TheBlueMatt/b...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
TheBlueMatt
TheBlueMatt
江湖只有他的大名,没有他的介绍。