该提案(RSKIP 178)旨在改进RSK区块链的安全性,通过引入“外部确认哈希率”机制,使RSK节点能够计算活跃的SHA256哈希率,检测与攻击相关的活跃哈希率变化,并将所有活跃的SHA256哈希率累积到RSK区块链中,从而提高抵抗双重支付攻击的能力。该机制不仅包括比特币哈希率,还可能包括来自比特币分叉的哈希率,以此增强RSK的安全性。
RSKIP | 178 |
---|---|
Title | 外部确认哈希率 |
Created | 2020年9月 |
Author | SDL |
Purpose | Sec |
Layer | Core |
Complexity | 2 |
Status | Draft |
discussions-to |
兼容分叉的包含式联合挖矿(IFAMM)协议提出了一种适用于联合挖矿区块链的新安全模型。如果区块链实现了 IFAMM 协议,并且满足模型的假设,则该模型可确保防止大型双花攻击,通过使攻击可见、可归因、需要至少 51% 的比特币矿工合谋,更重要的是,需要一个有界的时间,其中界限取决于攻击者的哈希率,但可以提前知道。可以调整界限参数,以便在发生攻击时,社区可以协调行动,例如安排手动使区块无效,或通过侧链(例如社交网络和论坛)执行硬分叉,以阻止攻击。
此 RSKIP 代表了实现 IFAMM 模型下的安全性所需的对 RSK 共识的更改之一。
对没有补贴的独立工作量证明链的密码经济安全的主要贡献是高额的交易费用。然而,在像 RSK 这样受联合挖矿保护的比特币侧链中,比特币矿工和联合矿工之间存在战略激励对齐,从而为侧链的安全性提供了两个额外的保证。首先,如果侧链的哈希率接近主链的哈希率,则可以继承诚实多数属性。其次,由于比特币矿工在区块中识别自己,因此对侧链的攻击变得可归因,或者通过直接识别参与攻击的矿池,或者通过突然删除区块中恶意矿池的识别信息。尽管如此,RSK 更进一步,部署了 Armadillo 系统以提供分叉感知。Armadillo 创建了一个时间窗口,以在发生长时间的重组尝试时触发社区的紧急响应。但是,Armadillo 需要单独的通信通道,并且至少需要一个诚实的节点来监控比特币网络的分叉。 IFAMM 协议(此 RSKIP 只是其中的一部分)基于一个安全模型,该模型捕获了 Armadillo 的优势,但将其去中心化。IFAMM 协议非常适合 RSK,因为它不仅关注攻击者的哈希率能力,还关注成功攻击所需的处理时间。
此 RSKIP 提出了一项共识变更,使 RSK 节点能够:
计算活跃的 SHA256 哈希率并检测与正在进行的攻击兼容的活跃哈希率的变化
将所有活跃的 SHA256 哈希率累积到 RSK 区块链中,而与直接参与联合挖矿的哈希率数量无关。这种额外的哈希率确认侧链区块,从而提高了基于长区块链重组的双花攻击的安全性。此外,累积的哈希率不仅可以捕获 100% 的比特币哈希率,还可以捕获来自比特币分叉的哈希率。
RSK 区块头是以下元素的列表:
parentHash, unclesHash, coinbase,stateRoot, txTrieRoot, receiptTrieRoot, logsBloom, difficulty, number, gasLimit, gasUsed, timestamp, extraData, paidFees, minimumGasPrice, uncleCount, ummRoot [, mergeMiningFields ]
mergeMiningFields 如下:
bitcoinMergedMiningHeader,
bitcoinMergedMiningMerkleProof,
bitcoinMergedMiningCoinbaseTransaction
我们将 mergeMiningProof 定义为一个包含 mergeMiningFields 的列表。
区块编码为:
blockHeader, transactions, uncles
uncles 是 RSK 区块头的列表。我们将 heavyblock 定义为一个具有某些属性的 mergeMiningProof,这些属性将在共识中得到验证。
我们扩展 uncle 列表,以在所有 RSK 区块头之后包含多个 heavyblock 元素(稍后定义)。为了保持语义连贯性,uncles 字段被重命名为 difficultyContributors。字段 uncleCount 被重命名为 difficultyContribution。
difficultyContributors 将是一个包含两个元素的 RLP 列表:第一个是旧的 uncles 列表。下一个是新的 heavyblocks 列表。
difficultyContributors = { uncles , heavyblocks }
difficultyContributors 也将是一个包含两个元素的 RLP 列表:第一个称为 immediateContribution,表示 uncle 贡献的难度。第二个称为 delayedContribution,表示确认 heavyblock 所做的贡献。
difficultyContributors = { immediateContribution , delayedContribution }
uncles 中引用的 uncle 的最大数量将从 10 减少到 6。
heavyblocks 中引用的 heavyblock 的最大数量将为 2。
比特币区块头包含以下字段:
字段 | 目的 | 大小(字节) |
---|---|---|
Version | 区块版本号 | 4 |
hashPrevBlock | 前一个区块头的 256 位哈希值 | 32 |
hashMerkleRoot | 基于区块中所有交易的 256 位哈希值 | 32 |
Time | 自 1970-01-01T00:00 UTC 以来的当前区块时间戳,以秒为单位 | 4 |
Bits | 当前的目标,采用紧凑格式 | 4 |
Nonce | 32 位数字 | 4 |
我们定义如何将 Bits 字段转换为可以与 RSK 区块难度进行比较的目标难度。
Bits 字段以紧凑格式存储。设 Bits 为字节数组 { E,Q1,Q2,Q3 }。设 M 为整数值 (Q1 << 16 + Q2 << 8 + Q3)(即以大端方式解释的 Q 数组)。比特币目标计算为 M*2^(8(E-3))。我们定义 btcDifficulty0 = 2^256 / target。请注意,btcDifficulty0 比比特币区块难度高 2^32 倍。
我们定义函数 getPoWInfo() 来检查所有类型的区块(主链、uncle 和 heavyblocks 列表中的元素)的有效性。这意味着检查普通 RSK 区块的工作量证明有效性的函数已更改为调用 getPoWInfo()。这是因为一些 RSK 区块可以是锚定 heavyblock。
首先,我们定义一个辅助函数 getMMInfo():
function getMMInfo()
参数:
返回值:
x = bitcoinMergedMiningCoinbaseTransaction of mergeMiningFields
midstate40 = x 的前 40 个字节
tail = 跳过前 40 个字节后 x 的剩余字节
lastTag = tail 中 "RSKBLOCK:" 的最后一个 Index
byteCount = bigEndianToInt64(从偏移量 8 开始提取 midstate40 的 4 个字节)
mergeMined = (lastTag>=0)
if (not mergeMined) then
if ((tail.length>=169) and (tail.length<233)) or (byteCount==0)
return (false,false)
else
return (false,true)
else
expected = "RSKBLOCK:"+ RSKHashForMergedMining
rskTagPosition = expected 在 tail 中的最后一个 Index
if (rskTagPosition == -1) return (true,false)
if (rskTagPosition >= 64) return (true,false)
if (rskTagPosition !=lastTag) return (true,false)
if (tail.length - rskTagPosition > 169) return (true,false)
coinbaseLength = tail.length + byteCount;
if (coinbaseLength <= 64) return (mergeMined,false)
transactionHash = SHA256(tail) 从 midstate40 开始
coinbaseTransactionHash = reverseBytes(transactionHash)
if (not validMerkleTree(merkleRoot,coinbaseTransactionHash)) return (mergeMined,false)
return (mergeMined,true)
getMMInfo() 函数的逻辑与 rskj 中的 ProofOfWorkRule 中现有的逻辑非常相似,ProofOfWorkRule 必须更改为使用此函数。
如果 (isMMValid==true) 且 (mergeMined==true),则输入表示一个 锚定 heavyblock(它也可以是内部 uncle、外部 uncle 或主链区块)。
如果 (isMMValid==true) 且 (mergeMined==false),则输入表示一个 确认 heavyblock。
锚定 heavyblock 可以通过三种不同的方式引用:
为了从比特币区块链中识别 外部 uncle 锚定 heavyblock,必须扩展 ARMADILLO 数据以至少包含 14 个字节的 RSK 父区块 ID,或者与之关联的 4 个字节的比特币区块 ID。在 ARMADILLO 得到改进之前,此 RSKIP 建议使用当前的 ARMADILLO 标签来识别 uncle。这将使 uncle 的范围扩展到最多 64 的深度,这有助于在深度 64 以内的“无利害关系”双花。通过在 ARMADILLO 数据中仅包含先前 RSK 区块的比特币 pow 的两个字节,攻击概率降低了 2^16 倍。换句话说,考虑到 50% 的哈希率联合挖矿 RSK,攻击机会只会每 2.5 年自发发生一次。
请注意,rskj 中 SHA256Digest 类的 midstate 使用与此描述中使用的格式不同的格式。我们调用我们的变量 midstate40 以区分它们。
同样重要的是要注意,上述算法要求对于没有联合挖矿的区块,tail 大小必须等于或大于 169 个字节,但小于 233 个字节,否则 midstate 实际上是 SHA256 初始状态,而对于具有联合挖矿标签的标头,tail 大小必须小于 169 个字节。最后一次检查与当前检查 ProofOfWorkRule 执行的方式相同:
remainingByteCount = tail.length - rskTagPosition - 41
if (remainingByteCount > 128) return (true,false)
需要 169 个字节的 tail 是为了防止攻击者通过在之后指定起始位置来隐藏 RSK 标签。
function getPoWInfo()
参数:
返回值:
isValid = false
immediateDifficultyContribution =0
delayedDifficultyControbution =0
includeInBtcBlockReferences = false
if not fromHeavyblocksArray
// 所有 RSK 区块(uncle 或主链)都必须在
// RSK 区块难度下具有有效的工作量证明
if not rskProofOfWorkValid(rskBlockHeader,bitcoinMergedMiningHeader) then return
(mergeMined,isMMValid) =getMMInfo(mergeMiningProof)
if not isMMValid return
isHBTimeValid = abs( bitcoinMergedMiningHeader.timeStamp - rskBlockHeader.timeStamp) < 300
if not isHBTimeValid return
btcDifficulty0 =getBtcDifficulty0(bitcoinMergedMiningHeader)
isPotentialHeavyBlock=(btcDifficulty0 >= difficulty)
if (isPotentialHeavyBlock)
isHeavyblock = btcProofOfWorkValid(bitcoinMergedMiningHeader) return
else
isHeavyblock = false
if not mergemined
// 这只能是一个确认 heavyBlock
if (not fromHeavyblocksArray) return
if (not isHeavyblock) return
// 我们检查是否注册了一个 btc 父级
if btcBlockpreviouslyIncluded(bitcoinMergedMiningHeader.getBlockHash()) return
delayedDifficultyControbution = C(rskBlockHeader,bitcoinMergedMiningHeader)
includeInBtcBlockReferences = true
if not isHeavyblock and mergemined
if (fromHeavyblocksArray) return
// 这是一个正常区块或 uncle 区块
immediateDifficultyContribution = R(rskBlockHeader,bitcoinMergedMiningHeader)
if not previouslyIncluded(bitcoinMergedMiningHeader.parent) return
// uncle 已经检查了以前的包含,并且 uncle 包含深度
// 短于 IFAMM 深度,因此我们不需要再次检查。
// 此检查不应更改任何内容,并且可以用作断言
if btcBlockpreviouslyIncluded(bitcoinMergedMiningHeader.getBlockHash()) return
if isHeavyblock and mergemined
// 这是:
// * 内部 uncle 锚定 heavyblock 或
// * 外部 uncle 锚定 heavyblock
// * 主链锚定 heavyblock
includeInBtcBlockReferences = true
if (fromHeavyblocksArray)
// 外部 uncle 锚定 heavyblock
immediateDifficultyContribution = C(RSKblockHeader,bitcoinMergedMiningHeader)
else
// 内部锚定 heavyblock 或 uncle 锚定 heavyblock
immediateDifficultyContribution = A(rskBlockHeader,bitcoinMergedMiningHeader)
else
// fromHeavyblocksArray 中的元素必须是以比特币难度解决的区块
if fromHeavyblocksArray return
isValid = true
return
在所示的伪代码中,btcProofOfWorkValid() 检查比特币标头的工作量证明是否与比特币标头中指定的难度匹配。该算法计算比特币标头指定的 btcDifficulty0,并检查它是否高于包含它的 RSK 区块的难度。调用函数 getMMInfo() 检查 bitcoinMergedMiningMerkleProof 与 mergeMiningProof 的其他两个字段是否正确,根据用于验证联合挖矿的相同共识规则。
每个联合挖矿证明,在主链中、在 uncle 列表中或在 heavyblocks 列表中都必须使用 getPoWInfo() 方法进行验证。如果该方法返回 isValid==false,则该区块无效。如果该方法返回 iincludeInBtcBlockReferences==true,则这意味着它是一个锚定或确认 heavyblock,因此关联的比特币区块哈希必须包含在 btcBlockReferences 列表中,该列表可以被 btcBlockPreviouslyIncluded() 引用。
如果具有给定哈希的比特币标头包含在 btcBlockReferences 列表中,则函数 btcBlockPreviouslyIncluded() 返回 true。此数组维护过去 256 个区块中包含的所有 heavyblock 的列表。该数组不需要存储,因为每次都可以从过去 256 个区块中的 heavyblock、uncle 和主链区块重新计算它。请注意,引用可能形成 DAG,因此包含的 heavyblock 可能在过去 256 个区块中具有多个子项。
让我们将 A 称为锚定 heavyblock 对链累积难度的贡献。
让我们将 R 称为比特币标头难度未达到 btcDifficulty0 的普通 RSK 区块的难度贡献。
让我们将 C 称为确认 heavyblocks 对链累积难度的贡献。
A、R、C 是当前 RSK 区块头和 merge-mining 字段引用的比特币区块头的函数。
我们提出以下函数:
A=btcDifficulty0/2
R=difficulty/2
C=btcDifficulty0
这些公式需要使用 256 位算术。此分配平均最多高估 RSK 区块链累积难度 1/20(RSK 和比特币之间的平均区块间隔的比率),我们认为此误差足够低以优先选择简化的公式。
精确值由以下公式给出:
q = btcDifficulty0/difficulty R = difficultyq/(2q-1) A = btcDifficulty0q/(2q-1)
C=btcDifficulty0
这些公式可能需要高达 512 位的算术运算。
请注意,R 和 C 贡献于 de immediateContribution 字段,但 A 贡献于 delayedContribution 字段。难度贡献不会直接应用于累积难度:这些值被压缩到 difficultyContribution 字段(这可能会导致一定的精度损失),并且只有这个量会被贡献回累积难度。这使得从 difficultyContribution 和 difficulty 字段轻松计算累积难度。
delayedContribution 在 40 个区块后应用于累积难度。
为了构建 immediateContribution 和 delayedContribution 字段,将它们的实际值乘以 1024,然后加在一起,然后除以 RSK 区块 difficulty。因此,difficultyContribution 字段将按 1024 缩放存储。这保证了 heavyblock 的 0.1% 精度,而不会占用太多空间。对于比特币区块(其难度约为 RSK 难度的 40 倍),精度为 0.0025%。对于难度在 RSK 的 1 到 2 倍之间的比特币现金区块,精度为 0.1%。
Sha256Digest midstate 的长度为 52 个字节。要初始化以用于 RSK 联合挖矿,它要求前 8 个字节和最后 4 个字节设置为零。这是因为 Sha256Digest midstate 允许从流中的任何点开始,而 RSK 协议要求起始点与 64 字节的边界匹配。
Sha256Digest midstate 的映射:
0: xBuf (4 字节数组) 由 RSK 清零(用于处理子字数据的缓冲区)
4: xBufOff (int32) 由 RSK 清零(填充的 xBuf 的偏移量)
8: byteCount (int64) <--- midstate40 从此处开始
16: H1 (uint64)
20: H2 (uint64)
24: H3 (uint64)
28: H4 (uint64)
32: H5 (uint64)
36: H6 (uint64)
40: H7 (uint64)
44: H8 (uint64) <--- midstate40 在此字段后结束
48: xOff (int32) 由 RSK 清零(在 misdtsate 之后未更新到哈希中的字数(模 64))
在 Nakamoto 共识中,如果在交易被包含后有 N 个区块确认,则确认交易。在 IFAMM 模型中,我们建议经济参与者也等待 N*v 时间,其中 v 是平均 RSK 区块间隔(目前为 30 秒)。
已经采取了几个设计选择。本节介绍最相关的。
向 RSK 标头添加新字段会增加轻节点的带宽消耗。为了避免向 RSK 区块头添加新字段,heavyblock 与 uncle 一起打包在 difficultyContributors 字段中。这在语义上是有意义的,因为 uncle 和 heavyblock 在协议中具有相似的角色:有助于区块的累积难度。
在 difficultyContributors 字段中引用多个 heavyblock 有两个原因:
虽然平均 RSK 区块现在比比特币现金区块向区块链转移更多的难度,但这归因于 uncle 区块的存在。虽然当前的 RSK 哈希率比比特币现金高 23 倍,但 RSK 区块的实际难度略低于比特币现金区块。因此,RSK 可以引用比特币现金 heavyblock。
delayedContribution 在 60 个区块后应用于累积难度。这是为了阻止攻击和意外情况。如果所有难度贡献都是立即的,那么:
通过延迟贡献,第一个问题被消除,因为诚实的分叉也会在恶意分叉增加其难度之前引用确认 heavyblock。
第二个问题得到了缓解,因为通过延迟,攻击者需要通过挖掘自私区块来赶上诚实链才能实现优势。由于陈旧区块的贡献,该优势可能约为 40 个区块,但攻击者也会获得 1 到 40 个区块的劣势,因为他必须恢复已确认的交易才能进行双花。支付金额越高,受害者将等待确认的区块越多。模拟表明,在难度转移延迟 60 个区块的情况下,攻击者仍然需要超过 40% 的 RSK 哈希率才能尝试恢复 20 个区块的双花。
此更改是硬分叉,因此必须更新所有完整节点。还应更新 SPV 轻客户端和区块浏览器。
待定
至少需要在以下位置修改 rskj 代码:
通过增加其成本(达到比特币级别的密码经济安全性)或通过迫使攻击者在整个支付确认间隔内公开攻击,在比特币区块中留下锚定 heavyblock 的痕迹并减少转移到 RSK 的累积哈希率,此 RSKIP 可保护 RSK 网络免受大量双花攻击。
但是,某些双花攻击的变体,例如隔离受害者节点,仍然需要进行额外的更改才能防止。IFAMM 模型需要的这些其他更改将在其他 RSKIP 中指定。
通过 CC0 放弃版权和相关权利。
- 原文链接: github.com/rsksmart/RSKI...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!