py-evm系列译文,有不当之处请联系改正,原文如下:https://py-evm.readthedocs.io/en/latest/guides/creating_opcodes.html

py-evm系列译文之2-Guides翻译4:创建操作码

创建操作码

操作码只是一个以BaseComputation 实例作为唯一参数的函数。如果操作码函数具有返回值,则在正常VM执行期间将丢弃该值。

这是一些简单的例子。

1
2
3
4
5
6
7
8
9
10
11
def noop(computation):
"""
一个无所事事的操作码 (甚至不消耗gas)
"""
pass

def burn_5_gas(computation):
"""
一个只是简单消耗5gas的操作码
"""
computation.consume_gas(5, reason='吃你5 gas 咋滴?')

as_opcode()助手

虽然这些示例表明了简单的逻辑,但操作码传统来说有一种固有的gas成本。Py-EVM提供了一种抽象,允许将气体消耗与操作码逻辑分离,这对于操作码的gas成本在不同VM规则之间变化但其逻辑保持不变的情况非常方便。

eth.vm.opcode.as_opcodelogic_fnmnemonicgas_cost

  • logic_fn参数应该是一个可调用的符合API操作码的函数调用?(这里有点疑惑),采取*~eth.vm.computation.Computation*实例作为其唯一的参数。
  • mnemonic是一个字符串,如'ADD''MUL'
  • gas_cost是执行此操作码的gas成本

返回值是一个执行logic_fn之前将消耗的gas_cost的函数**(???)**

as_opcode()助手的用法:

1
2
3
4
5
6
7
def custom_op(computation):
... # 操作码逻辑

class ExampleComputation(BaseComputation):
opcodes = {
b'\x01': as_opcode(custom_op, 'CUSTOM_OP', 10),
}

操作码作为类

有时,将操作码作为类,在相似的操作码之间共享通用逻辑,或跨多个fork规则使用相同的操作码时可能会有所帮助。在这些情况下,将操作码作为类实现可能是正确的选择。这就像__call__在类上实现符合操作码API 的方法一样简单,将单个Computation实例作为唯一参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class MyOpcode:
def initial_logic(self, computation):
...

def main_logic(self, computation):
...

def cleanup_logic(self, computation):
...

def __call__(self, computation):
self.initial_logic(computation)
self.main_logic(computation)
self.cleanup_logic(computation)

利用这种模式,可以重复使用整体结构以及大部分逻辑,同时仍然允许一种机制来覆盖操作码逻辑的各个部分。