【翻译】BCH难度调整算法-ASERT DAA(aserti3-2d)——2020.11.15激活

概要

新的难度调整算法“aserti3-2d”(简称为“ASERT”)于BCH在2020年11月份的更新中被激活。激活方式基于MTP(median?? ),最后的前叉块将会被作为锚定块。

动机

  • 消除难度值与算力的周期性波动
  • 为了减少稳定矿工与机枪池矿工之间的收益差距
  • 保持平均区块间隔接近10分钟
  • 使平均交易确认时间接近目标时间

技术背景

BCH在2017年十一月的更新中介绍了一种简单的移动平均方法作为难度调整算法。不幸的是,这次更新引入了周期性的难度波动,导致长时间无法确认交易后紧随而来的是一段时间的快速出块。这种出块的不稳定性降低了用户对BCH的期望并且对长时间挖掘BCH矿工不公平。

在对一类基于移动指数平均线(exponential moving average,EMA)的难度算法深入研究后,Mark Lundeberg在2019年发展了一种绝对进度指数上升目标(Absolutely Scheduled Exponentially Rising Targets,ASERT)算法[1],并在2020年对该算法进行了全面的描述。Jacob Eliosoff在2018年和Werner et. al[6]在2016年分别独立的发现了该算法的等价形式。

ASERT没有在2017年十一月更新中提出的DAA方法所具有的波动性,相反地,它在许多方面表现出了引人注目的性质,例如它不需要额外的规则就可以抵抗奇异性[15],不会产生舍入/近似误差的累积。

针对其它一系列稳定算法的仿真对比中[2],ASERT算法在以下所有条件下都有最佳的表现:

  • 平均出块时间最接近理想目标时间:600秒
  • 平均交易确认时间最接近目标时间。
  • 减少了机枪池策略的优势,从而最大化稳定矿工的收益。

规范

术语和约定

分叉块:根据新的共识规则挖出的第一个块

锚定块:分叉块的前一个块

要求

难度目标计算

当前区块的难度目标通过DAA机制进行调整。

aserti3-2d算法可以通过下面的公式来描述:
KaTeX parse error: Undefined control sequence: \- at position 52: …me\_delta-ideal\̲-̲block\_time*(he…
式中, a n c h o r _ t a r g e t − − 锚 定 区 块 头 中 以 无 符 号 256 整 数 表 示 的 n B i t s 值 anchor\_target--锚定区块头中以无符号256整数表示的nBits值 anchor_target256nBits

t i m e _ d e l t a − − 以 秒 为 单 位 的 有 符 号 整 数 , 表 示 当 前 区 块 头 中 的 时 间 戳 与 锚 定 区 块 前 一 个 区 块 时 间 戳 的 差 值 time\_delta--以秒为单位的有符号整数,表示当前区块头中的时间戳与锚定区块前一个区块时间戳的差值 time_delta

i d e a l _ b l o c k _ t i m e − − 表 示 平 均 出 块 时 间 的 常 数 值 , 600 秒 ideal\_block\_time--表示平均出块时间的常数值,600秒 ideal_block_time600

h e i g h t _ d e l t a − − 当 前 区 块 高 度 和 锚 定 区 块 高 度 的 差 值 height\_delta--当前区块高度和锚定区块高度的差值 height_delta

h a l f l i f e − − 常 数 值 , 有 时 候 也 称 为 ′ t a u ′ , 主 网 取 值 为 172800 ( 秒 ) halflife--常数值,有时候也称为'tau',主网取值为172800(秒) halflifetau172800

n e x t _ t a r g e t − − 以 整 数 形 式 表 示 的 下 一 区 块 的 难 度 目 标 next\_target--以整数形式表示的下一区块的难度目标 next_target

通过使用定点整数算法和对 2 x 2^x 2x项的三次多项式逼近来拟合上述公式。

用做输入和输出的“难度目标”是以256位整数目标值的紧凑形式表示,这是与区块头中的“nBits”字段一致的。

Python代码,使用Python3语法:

def next_target_aserti3_2d(
    anchor_height: int,       # height of the anchor block.
    anchor_parent_time: int,  # timestamp (nTime) of the parent of the anchor block.
    anchor_bits: int,         # 'nBits' value of the anchor block.
    current_height: int,      # height of the current block.
    current_time: int,        # timestamp of the current block.
) -> int:                     # 'target' nBits of the current block.
    ideal_block_time = 600    # in seconds
    halflife = 172_800        # 2 days (in seconds)
    radix = 2**16             # 16 bits for decimal part of fixed-point integer arithmetic
    max_bits = 0x1d00_ffff    # maximum target in nBits representation
    max_target = bits_to_target(max_bits)  # maximum target as integer

    anchor_target = bits_to_target(anchor_bits)
    time_delta = current_time - anchor_parent_time
    height_delta = current_height - anchor_height  # can be negative
    # `//` is truncating division (int.__floordiv__) - see note 3 below
    exponent = time_delta - ideal_block_time * (height_delta + 1) // halflife

    # Compute equivalent of `num_shifts = math.floor(exponent / 2**16)`
    num_shifts = exponent >> 16

    exponent = exponent - num_shifts * radix
    factor = ((195_766_423_245_049 * exponent +
               971_821_376 * exponent**2 +
               5_127 * exponent**3 +
               2**47) >> 48) + radix
    next_target = anchor_target * factor

    # Calculate `next_target = math.floor(next_target * 2**factor)`
    if num_shifts < 0:
        next_target >>= -num_shifts
    else:
        # Implementations should be careful of overflow here (see note 6 below).
        next_target <<= num_shifts

    next_target >>= 16
    if next_target == 0:
        return target_to_bits(1)   # hardest valid target

    if next_target > max_target:
        return max_bits            # limit on easiest target
    return target_to_bits(next_target)

注意:

  1. 参考实现使用了有符号整数算法,实际实现中可能是使用严格的无符号整数算法。
  2. 所有实现都应该在计算指数时严格的避免使用浮点算法。
  3. 在进行指数计算时,必须使用截断整数除法[7,10],即’//’。
  4. ?空白
  5. 格式转换函数bits_to_target()和target_to_bits()实现了难度目标值以紧凑型“nBits”和无符号256位整数表示之间的转换。这些函数的例子可以在C++或Python3的参考实现中找到。
  6. 计算“factor”时的多项式近似必须以64位无符号整数或者更好的形式表示。如果使用有符号64位整数将导致溢出。由于指数是有符号的,可能需要将其强制转换为无符号64位整数。在像Java这样的编程语言中,long类型总是有符号的。无符号移位操作>>>48必须除以 2 48 2^{48} 248
激活

ASERT算法将根据顶级升级规范被激活[3]

锚定区块

ASERT算法要求选择一个锚定区块来安排将来难度目标计算的进度。

MTP大于/等于激活时间的第一个块,将被用作后续ASERT计算的锚定块。

锚定区块对应于ASERT DAA之前的规则所挖出的最后一个区块。

注意:

  1. 锚定区块的高度和难度目标(nBits)被用作ASERT预定目标的绝对基础。同时使用了锚定区块的父区块中的时间戳(nTime)字段
  2. 锚定区块的高度、时间戳和难度目标(nBits)在进行升级之前是不知道的。具体实现必须由区块链升级动态确定。一旦通过足够的累积链上工作或检查点合并了网络升级,具体实现即可简单地对已知高度,难度目标(nBits)和关联的父区块时间戳进行硬编码。具体实现的硬编码也有其它的等价形式,例如nBits值或者从创世区块的时间偏移。
REQ-ASERT-TESTNET-DIFF-RESET (重置测试网络难度)

在测试网中,将会包含一条额外的规则:任何区块的时间戳与父区块的时间戳如果超过1200秒就必须将难度值设置为: m a x _ b i t s ( 0 x 1 d 00 f f f f ) max\_bits(0x1d00ffff) max_bits(0x1d00ffff)

需求/设计决策的理由和评价

  1. 选择锚定区块的决定

选择过去足够久远的区块会略微降低编程难度,但可能导致在升级时难以改变难度调整机制。

原有的DAA算法挖出的最后一个区块被选做锚定区块,因为改区块是最接近新算法的锚点,可以平滑的过渡到新算法。

  1. 回避浮点数计算

通常在编程语言上实现新的DAA调整机制是不保证符合IEEE-754浮点运算规则的。浮点计算的结果通常依赖于编译器、解释器或硬件。

因此强烈建议所有的运算都使用纯粹的整数和高度特定的运算符来保证在所有的实现中都获得相同的难度值。

  1. 半衰期的选择

半衰期选择两天( h a l f l i f e = 2 ∗ 24 ∗ 3600 halflife=2*24*3600 halflife=2243600),等效于基于 e x e^x ex的时间常数 2 ∗ 144 ∗ l n ( 2 ) 2*144*ln(2) 2144ln(2)或者 a s e r t i 3 − 415.5 aserti3-415.5 aserti3415.5。之所以如此选择,是因为 ,同时也便于理解:每时间表上区块时间戳的两天以前,难度值都会加倍(?怎么理解?)

  1. 多项式近似的选择

难度调整机制是调节算力的控制系统反馈回路的一部分,指数函数和它的整数近似是系统传递函数的一部分。因此难度调整机制适用于确保控制系统稳定性的各项标准指南。在这些控制系统的传递函数中,往往对非线性微分要比分线性积分敏感的多。因此,我们要求传递函数具有如下性质:(a) 单调性,(b) 连续性,© 比我们的多块统计基底噪声具有更好的精度和微分非线性,(d) 具有简单的实现,(e) 不差于目前单块统计基底噪声的积分非线性。

一个简单的,快速计算 2 x , 0 ≤ x < 1 2^x,0\le x<1 2x,0x<1的立方近似满足我们的所有要求。在此范围内,他的绝对误差范围保持在 0.013 % 0.013\% 0.013%以下[8]。我们发现 2 x + n = 2 n ∗ 2 x 2^{x+n}=2^n*2^x 2x+n=2n2x的性质对于将其拓展到指数函数的完整定义域 ( ∞ , − ∞ ) (\infty,-\infty) (,)是有用的。我们的立方近似给出了 f ( 0 ) = 1 f(0)=1 f(0)=1 f ( 1 ) = 2 f(1)=2 f(1)=2的准确值,这意味着我们可以使用这个性质而不必担心近似函数定义域边缘的不连续性。

首先,有些非线性微分(DNL)方面的问题。我们的目标时确保我们的算法引入的噪声,不超过数据集中固有噪声的 25 % 25\% 25%。我们的算法通过使用两天(288个块)作为半衰期,尝试有效地估计最近一段时间算力的特征。我们期望块间隔的指数分布具有600秒的标准差。在两天半衰期的基础上,我们估计的算力中的基底噪声应该在 1 / 288 ∗ 600 \sqrt{1/288}*600 1/288 600秒左右,或使用 35.5 35.5 35.5秒作为近似。由于在两个地方被16位运算符: 172800 sec ⁡ / 65536 = 2.6367 sec ⁡ 172800 \sec/65536=2.6367 \sec 172800sec/65536=2.6367sec限制,我们选定的近似方法能够在大多数情况下达到3秒的精度。受限于最坏情况下nBits值只有15位的精度,我们的近似方法此时的精度为 8 sec ⁡ 8 \sec 8sec。8秒的最坏情况不属于本项工作讨论的范围,因为此时需要对区块头的结构做出更改。由于最坏情况下的15为nBIts值尾数问题,我们在最坏情况下的步长为 0.00305 % 0.00305\% 0.00305%[11]。在15位nBits值尾数范围之外,我们近似算法在最坏情况下的精度为 0.0021 % 0.0021\% 0.0021%。总体而言,我们认为这是令人满意的DNL性能。

其次,有些非线性积分(INL)方面的问题。仿真测试表明,难度值和算力调节性能对非线性积分非常不敏感。我们在 a s e r t i 1 aserti1 aserti1算法中发现即使使用 f ( x ) = 1 + x f(x)=1+x f(x)=1+x作为 2 x 2^x 2x的近似,在与 2 x + n = 2 n ∗ 2 x 2^{x+n}=2^n*2^x 2x+n=2n2x特性进行耦合时,尽管有 6 % 6\% 6%的最坏情况[12,13],也能获得令人满意的结果。一个近似函数的非线性积分性质较差时依然显示了很好的算力调节能力,不过对于指定的算力变化,其漂移量将有所不同,具体取决于指数(模数1)在[0,1)域中的位置。当INL变化 + / − 1 % +/- 1\% +/1%,对于给定难度值或难度目标,一个区块的时间戳最终可能比计划提前或延后172800秒的 1 % 1\% 1%。然而,出于谨慎,并且由于实现更高精度是比较容易的,我们选择的目标是使INL等于或小于一个区块可能引起的典型漂移。在两天的半衰期窗口之外,一个区块的方差包含 600 / 172800 = 0.347 % 600/172800=0.347\% 600/172800=0.347%。我们立方近似的INL性能比要求的范围好于[14] 0.013 % 0.013\% 0.013%

  1. 难度位字段(nBits)与256位难度目标表示之间的转换

因为在ASERT算法中设计256位整数的计算相对较少,同时执行频率较低,所以更复杂的操作符类似于在难度算法的输入/输出数据,即紧凑形式表示的难度目标(nBits)上直接进行算术运行是没有必要的。

此外,在现有的实现中可以使用256位(甚至bignum)算法,并且可以在以前的DAA中使用它。 对性能的影响可以忽略不计。

  1. 定点数16位精度的选择

nBIts字段的形式由8位以256为基底的指数和24位尾数组成。尾数值不能小于 0 x 008000 0\rm{x}008000 0x008000,这意味着最坏情况下尾数只提供15位精度。之所以选择16位精度是确保我们定点数运行中能够满足15位nBits的限制。

  1. 名称的选择

算法名称“aserti3-2d”的选择基于以下几点原因:

  • “i”指只针对整数运算
  • “3”指指数的立方近似
  • “2d”指两天的半衰期(172800秒)

关于实现的一些建议

实现算法中的计算过程时必须避免引入任何舍入误差。舍入必须完全按照算法中指定的进行。 实际上,要保证这一点,您可能需要专门使用整数算术。

使用有符号整数并使用移位的实现必须确保该移位是算术移位。

注意:在C++编译器中,右移负号整数即将编程标准[5],但在C ++ 20之前是形式未指定的行为。实际上,C/C++编译器通常对有符号数执行算术移位。 建议实现者通过编译时声明或单元测试来验证良正确性。

参考实现

  • C++实现(见pow.cpp):https://reviews.bitcoinabc.org/D7174
  • Python3实现(见contrib/testgen/validate_nbits_aserti3_2d.py): https://gitlab.com/bitcoin-cash-node/bitcoin-cash-node/-/merge_requests/692
  • Java实现:https://github.com/pokkst/asert-java

测试向量

适用于验证aserti3-2d算法其他实现的测试向量可在以下位置找到:

https://gitlab.com/bitcoin-cash-node/bchn-sw/qa-assets/-/tree/master/test_vectors/aserti3-2d

或者在:

https://download.bitcoincashnode.org/misc/data/asert/test_vectors

致谢

感谢Mark Lundeberg授予发表ASERT论文的许可,Jonathan Tooming初步在Python和C++上实现了ASERT算法,更新了仿真框架并且评估了不同的难度算法。

感谢Jacob Eliosoff, Tom Harding和Scott Roberts在EMA族和其它被考虑作为BCH难度调整机制替代算法上的评估工作,同时感谢以下评论以及他们提出的宝贵改进建议:

  • Andrea Suisani (sickpig)
  • BigBlockIfTrue
  • Fernando Pellicioni
  • imaginary_username
  • mtrycz
  • Jochen Hoenicke
  • John Nieri (emergent_reasons)
  • Tom Zander

参考文献

[1] “Static difficulty adjustments, with absolutely scheduled exponentially rising targets (DA-ASERT) – v2”, Mark B. Lundeberg, July 31, 2020

[2] “BCH upgrade proposal: Use ASERT as the new DAA”, Jonathan Toomim, 8 July 2020

[3] Bitcoin Cash November 15, 2020 Upgrade Specification.

[4] https://en.wikipedia.org/wiki/Arithmetic_shift

[5] https://en.cppreference.com/w/cpp/language/operator_arithmetic

[6] “Unstable Throughput: When the Difficulty Algorithm Breaks”, Sam M. Werner, Dragos I. Ilie, Iain Stewart, William J. Knottenbelt, June 2020

[7] “Different kinds of integer division”, Harry Garrood, blog, 2018

[8] Error in a cubic approximation of 2^x for 0 <= x < 1

[9] Jonathan Toomim adaptation of kyuupichan’s difficulty algorithm simulator: https://github.com/jtoomim/difficulty/tree/comparator

[10] “The Euclidean definition of the functions div and mod”, Raymond T. Boute, 1992, ACM Transactions on Programming Languages and Systems (TOPLAS). 14. 127-144. 10.1145/128861.128862

[11] http://toom.im/bch/aserti3_step_size.html

[12] [f(x) = (1 + x)/2^x for 0, WolframAlpha.

[13] https://github.com/zawy12/difficulty-algorithms/issues/62#issuecomment-647060200

[14] http://toom.im/bch/aserti3_approx_error.html

[15] https://github.com/zawy12/difficulty-algorithms/issues/62#issuecomment-646187957

许可

该规范使用Creative Commons CC0 1.0 Universal和GNU All-Permissive双重许可。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值