WTF-Solidity
WTF-Solidity copied to clipboard
require和assert的gas消耗对比问题
理论上require的报错会将余下的gas返回给user,而assert会全部没收,而15_Error中实验结果,是assert比require更少的损耗,问题出在哪里
可能是因为require里包含了报错提示字符,字符越长gas消耗越多。另外例子中代码比较少,可能代码长一些,才能看出差别。
@edddyguo 可以用钱包连公链测试一下差异,remix提供的默认节点返回的gas应该是实际执行指令的gas cost,跟公链有差别
我在相应的require和assert的下方加入了一个for循环100次的逻辑,测试结果和原来的一直,assert都是将剩下的gas返还给user了,考虑到编译器版本的问题,我用0.6.4的编译器也是同样的测试结果,不知道为啥和搜到的文档里面描述的不一样
@edddyguo 可以用钱包连公链测试一下差异,remix提供的默认节点返回的gas应该是实际执行指令的gas cost,跟公链有差别
一直是用的rinkeby测试的
Panic exceptions used to use the invalid opcode before Solidity 0.8.0, which consumed all gas available to the call. https://docs.soliditylang.org/en/latest/control-structures.html#revert 感觉可以看下字节码指令是revert还是invalid。
0.8.0以后,revert、require、assert的底层字节码都是revert。 revert的消耗量应该和要看自定义Error的参数数目有关。 assert在revert的时候会默认携带内建Error——Panic(1),它有1个Error参数,所以理论上会比不带Error参数的revert消耗多一些gas。 require(string)在revert的时候会是携带Error(string),虽然也只有1个参数,但是如果想描述清楚错误原因,一般需要比较长的字符串,所以通常是消耗的。
我深入研究了一下:
Assert
assert关键字的底层opcode在Solidity 0.8.0之前都是INVALID, 是会消耗所有的剩余gas的,然后将所有状态恢复到这个call之前
- AF: INVALID
On execution of any invalid operation, whether the designated INVALID opcode or simply an undefined opcode, all remaining gas is consumed and the state is reverted to the point immediately prior to the beginning of the current execution context.

assert关键字的底层opcode在Solidity 0.8.0之后都是REVERT, 而REVERT opcode只是一个简单的内存操作, revert(mem[ost:ost+len-1]),剩余的gas是会返还的
- A0-1: Memory Expansion An additional gas cost is paid by any operation that expands the memory that is in use. This memory expansion cost is dependent on the existing memory size and is 0 if the operation does not reference a memory address higher than the existing highest referenced memory address. A reference is any read, write, or other usage of memory (such as in a CALL).

Require
Require关键字的底层opcode不管在Solidity的哪个版本都是REVERT,因此都会返还剩余的gas

Revert
Revert 关键字跟Require一样,会返还所有剩余的gas,可以自己去做实验
Highlight
以上讨论的topic都是是否会返还剩余的gas,已经执行过的语句(即报错之前的语句)所消耗的gas是不会返还的,因为这一块已经占用了矿工们(现在是POS Validator)的资源了,如果不收费就会造成有人无成本攻击Ethereum生态了。
References
- https://github.com/wolflo/evm-opcodes/blob/main/gas.md#af-invalid
- https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a0-1-memory-expansion
- https://docs.soliditylang.org/en/v0.8.7/control-structures.html?highlight=assert%20gas#panic-via-assert-and-error-via-require
- https://ethereum.org/en/developers/docs/evm/opcodes/
我深入研究了一下:
Assert
assert关键字的底层opcode在Solidity 8.0之前都是INVALID, 是会消耗所有的剩余gas的,然后将所有状态恢复到这个call之前
- AF: INVALID
On execution of any invalid operation, whether the designated INVALID opcode or simply an undefined opcode, all remaining gas is consumed and the state is reverted to the point immediately prior to the beginning of the current execution context.
assert关键字的底层opcode在Solidity 8.0之后都是REVERT, 而REVERT opcode只是一个简单的内存操作,revert(mem[ost:ost+len-1]),剩余的gas是会返还的
- A0-1: Memory Expansion An additional gas cost is paid by any operation that expands the memory that is in use. This memory expansion cost is dependent on the existing memory size and is 0 if the operation does not reference a memory address higher than the existing highest referenced memory address. A reference is any read, write, or other usage of memory (such as in a CALL).
Require
Require关键字的底层opcode不管在Solidity的哪个版本都是REVERT,因此都会返还剩余的gas![]()
Revert
Revert关键字跟Require一样,会返还所有剩余的gas,可以自己去做实验Hightlight
以上讨论的topic都是
是否会返还剩余的gas,已经执行过的语句(即报错之前的语句)所消耗的gas是不会返还的,因为这一块已经占用了矿工们(现在是POS Validator)的资源了,如果不收费就会造成有人无成本攻击Ethereum生态了。References
- https://github.com/wolflo/evm-opcodes/blob/main/gas.md#af-invalid
- https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a0-1-memory-expansion
- https://docs.soliditylang.org/en/v0.8.7/control-structures.html?highlight=assert%20gas#panic-via-assert-and-error-via-require
- https://ethereum.org/en/developers/docs/evm/opcodes/
wow 详细
我深入研究了一下:
Assert
assert关键字的底层opcode在Solidity 8.0之前都是INVALID, 是会消耗所有的剩余gas的,然后将所有状态恢复到这个call之前
- AF: INVALID
On execution of any invalid operation, whether the designated INVALID opcode or simply an undefined opcode, all remaining gas is consumed and the state is reverted to the point immediately prior to the beginning of the current execution context.
assert关键字的底层opcode在Solidity 8.0之后都是REVERT, 而REVERT opcode只是一个简单的内存操作,revert(mem[ost:ost+len-1]),剩余的gas是会返还的
- A0-1: Memory Expansion An additional gas cost is paid by any operation that expands the memory that is in use. This memory expansion cost is dependent on the existing memory size and is 0 if the operation does not reference a memory address higher than the existing highest referenced memory address. A reference is any read, write, or other usage of memory (such as in a CALL).
Require
Require关键字的底层opcode不管在Solidity的哪个版本都是REVERT,因此都会返还剩余的gas![]()
Revert
Revert关键字跟Require一样,会返还所有剩余的gas,可以自己去做实验Hightlight
以上讨论的topic都是
是否会返还剩余的gas,已经执行过的语句(即报错之前的语句)所消耗的gas是不会返还的,因为这一块已经占用了矿工们(现在是POS Validator)的资源了,如果不收费就会造成有人无成本攻击Ethereum生态了。References
- https://github.com/wolflo/evm-opcodes/blob/main/gas.md#af-invalid
- https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a0-1-memory-expansion
- https://docs.soliditylang.org/en/v0.8.7/control-structures.html?highlight=assert%20gas#panic-via-assert-and-error-via-require
- https://ethereum.org/en/developers/docs/evm/opcodes/
bravo!
Note
另外,在REVERT opcode被正式引入之前,所有rollback操作只能通过INVALID opcode来执行,痛点就是虽然rollback了但仍然要消耗掉所有剩余的gas,资本效率非常低。且那个时候Solidity连Require和Revert关键字都还没有
Time logs
- 2016年8月22日 nmushegian 在这个PR中提出想引入一个新的opcode为
REVERT - 2017年2月7号 axic 正式编写 EIP-140
- 2017年3月16正式发布Solidity
0.4.10版本,一次性加入了Require关键字,Revert关键字,REVERTopcode的编译支持。 - 2017年9月14日发布EVM Megara (v1.7.0),支持
REVERTopcode。
BTW,从这里我们可以看出来好像是Solidity语言先支持,然后EVM再支持,这个有点违反我的直觉了,没想通。
References
- https://github.com/ethereum/EIPs/issues/140
- https://github.com/ethereum/EIPs/pull/206
- https://github.com/ethereum/solidity/releases/tag/v0.4.10
- https://github.com/ethereum/go-ethereum/releases/tag/v1.7.0