EIP-7543: EVM 任意精度十进制数学
此 EIP 添加了 OPCODE,允许对所有具有精确 gas 枚举的基本函数进行任意精度十进制浮点数计算。
Authors | 1m1 (@1m1-github) |
---|---|
Created | 2023-10-22 |
Discussion Link | https://ethereum-magicians.org/t/decimal-math-on-evm/16194 |
Table of Contents
摘要
此 EIP 添加了 任意精度十进制浮点数 OPCODE,用于通过 DECADD、DECNEG、DECMUL、DECINV 进行算术运算,并通过 DECEXP、DECLN、DECSIN 表达所有基本函数。所有十进制值,直至 int256 系数和指数所允许的最大精度,都以 c*10^q 的形式精确表示。所有已实现的算法都针对所有输入收敛,只要用户选择足够的精度。所有计算都是确定性的,并且 gas 以自下而上的方式精确嵌入。允许任意精度十进制基本函数将数学金融、机器学习、科学、数字艺术、游戏和其他领域引入 Ethereum。该实现是功能性的。
动机
目前,要计算非整数值的幂 a^b,需要大量的 Solidity 代码。 交易中最简单的任务例如是将波动率从年度转换为每日,这涉及取 16 次方根。
让用户/开发人员拥有与科学计算器相同的功能,可以创建具有更高复杂性的应用程序。
文件 BlackScholes.yul 和 Neuron.yul 演示了这些 OPCODE 如何简化数值智能合约代码。
为什么选择十进制?
要在二进制中表示像 0.1 这样的简单值,需要无限多的数字,因此无法在有限的二进制机器中精确表示。十进制类型更接近于人类运行的绝大多数数值计算。
eVm
EVM 是一个虚拟机,因此不受硬件的限制。通常,汇编语言提供的 OPCODE 模仿硬件的能力。在虚拟机中,我们没有这样的限制,并且没有什么可以阻止我们添加更复杂的 OPCODE,只要提供公平的 gas。同时,我们不想弄乱 OPCODE 库。EXP、LN 和 SIN 是通用函数,为以下方面开辟了道路:幂、三角学、积分、微分方程、机器学习、数字艺术等。
规范
十进制
十进制定义为
c * 10^q
其中 c 和 q 都是 int256。
符号上: a = ac * 10^aq b = bc * 10^bq 等等。
OPCODE 定义
0xd0 DECADD a+b -> c : (ac, aq, bc, bq, precision) -> (cc, cq) 0xd1 DECNEG -a -> b : (ac, aq) -> (bc, bq) 0xd2 DECMUL a*b -> c : (ac, aq, bc, bq, precision) -> (cc, cq) 0xd3 DECINV 1/a -> b : (ac, aq, precision) -> (bc, bq) 0xd4 DECEXP exp(a) -> b : (ac, aq, precision, steps) -> (bc, bq) 0xd5 DECLN ln(a) -> b : (ac, aq, precision, steps) -> (bc, bq) 0xd6 DECSIN sin(a) -> b : (ac, aq, precision, steps) -> (bc, bq)
precision
是所有计算中保留的位数。DECEXP 和 DECSIN 的 steps
是泰勒展开的步数。DECLN 的 steps
是连分数展开的深度。
为什么选择这些函数?
所提出的函数(+,-,*,/,exp,ln,sin)形成了一个小的集合,它们组合起来可以实现所有基本函数的计算,包括有限多个多项式、有理函数、三角函数、双曲函数和指数函数的和、积、根和组合,包括它们的逆函数。
a^b = exp(b * ln(a)) 给了我们幂和多项式。 cos(a) = sin(tau/4-a), tan(a)=sin(a)/cos(a) 等,给了我们所有的三角学。
结合算术,我们得到所有基本函数。
DECNEG 而不是 DECSUB
求反是比减法更通用的运算。OPCODE 应该尽可能基本,并且尽可能复杂。 出于同样的原因,我们有 DECINV 而不是 DECDIV。
DECSUB(a,b) = DECADD(a,DECNEG(b)) DECDIV(a,b) = DECMUL(a,DECINV(b))
DECEXP、DECSIN 通过泰勒级数
exp 和 sin 的泰勒级数在任何地方都收敛并且速度很快。误差下降的速度与步数的阶乘一样快。
DECLN 通过连分数
Ln 使用连分数在区间 ]0,2] 内快速收敛。该实现将输入缩放到此区间,并将结果正确地缩放回去。
本文件中关键词 “MUST”、”MUST NOT”、”REQUIRED”、”SHALL”、”SHALL NOT”、”SHOULD”、”SHOULD NOT”、”RECOMMENDED”、”NOT RECOMMENDED”、”MAY” 和 “OPTIONAL” 按照 RFC 2119 和 RFC 8174 中的描述进行解释。
理由
gas
所有上述 OPCODE 都是确定性的,因此可以确定 gas 成本。同时,计算很复杂并且依赖于输入。
拥有准确的 gas 成本对于避免节点上的能量攻击至关重要。
为此,底层的 uint256 库可以用 gas 累积来包装,如 ../assets/eip-EVM+/uint256_wrapped.go 中的参考实现所示。这给出了一种自下而上计算 gas 的方法,通过运行 OPCODE。
因为 EVM 解释器希望在实际运行 OPCODE 之前获得 gas 成本,所以我们运行 OPCODE 两次。第一次运行与第二次运行相同,是为了获得自下而上的 gas 成本,然后将其加倍以解释实际运行加上 gas 计算。最重要的是,我们添加了一个固定的模拟成本。
这给出了一个嵌入式 gas 计算,它适用于复杂的 OPCODE(参见 ../assets/eip-EVM+/gasEVMPlusEmulate.go 中的 gasEVMPlusEmulate)。
为了消除双倍 gas,我们可以找到一个取决于函数输入的 gas 使用量的上限。 或者,未来的 EIP 将提出以下建议:允许合约代码在累积 gas(在运行时)的同时运行,并在违反限制的情况下发生 panic,而无需提前知道成本。这仅适用于纯合约代码,定义为仅依赖于用户输入和合约内部字节码的代码。纯合约无法使用链中的状态,也无法调用其他合约。例如,纯数学函数将是纯合约。给定输入,纯合约是完全确定性的,允许用户离线(更便宜)估算 gas 成本,并且 EVM 在运行时发生 panic,而无需提前知道 gas。
由于成本取决于输入,模糊测试会给我们接近最坏的情况(TODO)。
向后兼容性
未发现向后兼容性问题。
由于 EVM 允许使用无效代码部署合约,因此在添加新 OPCODE 时,可能存在以前无效的代码变为有效的情况。可以将 EVM 设计为期望所有字节码的开头都有一个版本标签,或者(非异或)仅部署有效代码。这是任何新 OPCODE 的问题。
测试用例
../assets/eip-EVM+/decimal_float_test.go
参考实现
参考实现位于 ../assets/eip-EVM+/decimal_float.go 中
安全考虑
只要保证数值正确性并且公平地收集 gas,就没有安全考虑。
版权
通过 CC0 放弃版权和相关权利。
Citation
Please cite this document as:
1m1 (@1m1-github), "EIP-7543: EVM 任意精度十进制数学 [DRAFT]," Ethereum Improvement Proposals, no. 7543, October 2023. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7543.