WTF-Solidity icon indicating copy to clipboard operation
WTF-Solidity copied to clipboard

require和assert的gas消耗对比问题

Open edddyguo opened this issue 3 years ago • 9 comments

理论上require的报错会将余下的gas返回给user,而assert会全部没收,而15_Error中实验结果,是assert比require更少的损耗,问题出在哪里

edddyguo avatar Jul 13 '22 03:07 edddyguo

可能是因为require里包含了报错提示字符,字符越长gas消耗越多。另外例子中代码比较少,可能代码长一些,才能看出差别。

AmazingAng avatar Jul 13 '22 06:07 AmazingAng

@edddyguo 可以用钱包连公链测试一下差异,remix提供的默认节点返回的gas应该是实际执行指令的gas cost,跟公链有差别

MultiSuperK avatar Jul 13 '22 07:07 MultiSuperK

我在相应的require和assert的下方加入了一个for循环100次的逻辑,测试结果和原来的一直,assert都是将剩下的gas返还给user了,考虑到编译器版本的问题,我用0.6.4的编译器也是同样的测试结果,不知道为啥和搜到的文档里面描述的不一样

edddyguo avatar Jul 15 '22 06:07 edddyguo

@edddyguo 可以用钱包连公链测试一下差异,remix提供的默认节点返回的gas应该是实际执行指令的gas cost,跟公链有差别

一直是用的rinkeby测试的

edddyguo avatar Jul 15 '22 06:07 edddyguo

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个参数,但是如果想描述清楚错误原因,一般需要比较长的字符串,所以通常是消耗的。

CryptoRbtree avatar Oct 04 '22 08:10 CryptoRbtree

我深入研究了一下:

Assert

assert关键字的底层opcodeSolidity 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. image


assert关键字的底层opcodeSolidity 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).

image

Require

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

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/

0xkookoo avatar Oct 08 '22 04:10 0xkookoo

我深入研究了一下:

Assert

assert关键字的底层opcodeSolidity 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. image

assert关键字的底层opcodeSolidity 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).

image

Require

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

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 详细

AmazingAng avatar Oct 08 '22 04:10 AmazingAng

我深入研究了一下:

Assert

assert关键字的底层opcodeSolidity 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. image

assert关键字的底层opcodeSolidity 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).

image

Require

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

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!

dukedaily avatar Oct 08 '22 04:10 dukedaily

Note

另外,在REVERT opcode被正式引入之前,所有rollback操作只能通过INVALID opcode来执行,痛点就是虽然rollback了但仍然要消耗掉所有剩余的gas,资本效率非常低。且那个时候Solidity连RequireRevert关键字都还没有

Time logs

  • 2016年8月22日 nmushegian 在这个PR中提出想引入一个新的opcode为REVERT
  • 2017年2月7号 axic 正式编写 EIP-140
  • 2017年3月16正式发布Solidity 0.4.10 版本,一次性加入了Require关键字,Revert关键字,REVERT opcode的编译支持。
  • 2017年9月14日发布EVM Megara (v1.7.0),支持REVERT opcode。

BTW,从这里我们可以看出来好像是Solidity语言先支持,然后EVM再支持,这个有点违反我的直觉了,没想通。

image image image image

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

0xkookoo avatar Oct 08 '22 09:10 0xkookoo