jumptable. 是一个 [256]operation 的数据结构. 每个下标对应了一种指令, 使用operation来存储了指令对应的处理逻辑, gas消耗, 堆栈验证方法, memory使用的大小等功能.

jumptable

数据结构operation存储了一条指令的所需要的函数.

  1. type operation struct {
  2. // op is the operation function 执行函数
  3. execute executionFunc
  4. // gasCost is the gas function and returns the gas required for execution gas消耗函数
  5. gasCost gasFunc
  6. // validateStack validates the stack (size) for the operation 堆栈大小验证函数
  7. validateStack stackValidationFunc
  8. // memorySize returns the memory size required for the operation 需要的内存大小
  9. memorySize memorySizeFunc
  10. halts bool // indicates whether the operation shoult halt further execution 表示操作是否停止进一步执行
  11. jumps bool // indicates whether the program counter should not increment 指示程序计数器是否不增加
  12. writes bool // determines whether this a state modifying operation 确定这是否是一个状态修改操作
  13. valid bool // indication whether the retrieved operation is valid and known 指示检索到的操作是否有效并且已知
  14. reverts bool // determines whether the operation reverts state (implicitly halts)确定操作是否恢复状态(隐式停止)
  15. returns bool // determines whether the opertions sets the return data content 确定操作是否设置了返回数据内容
  16. }

指令集, 下面定义了三种指令集,针对三种不同的以太坊版本,

var ( frontierInstructionSet = NewFrontierInstructionSet() homesteadInstructionSet = NewHomesteadInstructionSet() byzantiumInstructionSet = NewByzantiumInstructionSet() ) NewByzantiumInstructionSet 拜占庭版本首先调用NewHomesteadInstructionSet创造了前一个版本的指令,然后增加自己特有的指令.STATICCALL ,RETURNDATASIZE ,RETURNDATACOPY ,REVERT

  1. // NewByzantiumInstructionSet returns the frontier, homestead and
  2. // byzantium instructions.
  3. func NewByzantiumInstructionSet() [256]operation {
  4. // instructions that can be executed during the homestead phase.
  5. instructionSet := NewHomesteadInstructionSet()
  6. instructionSet[STATICCALL] = operation{
  7. execute: opStaticCall,
  8. gasCost: gasStaticCall,
  9. validateStack: makeStackFunc(6, 1),
  10. memorySize: memoryStaticCall,
  11. valid: true,
  12. returns: true,
  13. }
  14. instructionSet[RETURNDATASIZE] = operation{
  15. execute: opReturnDataSize,
  16. gasCost: constGasFunc(GasQuickStep),
  17. validateStack: makeStackFunc(0, 1),
  18. valid: true,
  19. }
  20. instructionSet[RETURNDATACOPY] = operation{
  21. execute: opReturnDataCopy,
  22. gasCost: gasReturnDataCopy,
  23. validateStack: makeStackFunc(3, 0),
  24. memorySize: memoryReturnDataCopy,
  25. valid: true,
  26. }
  27. instructionSet[REVERT] = operation{
  28. execute: opRevert,
  29. gasCost: gasRevert,
  30. validateStack: makeStackFunc(2, 0),
  31. memorySize: memoryRevert,
  32. valid: true,
  33. reverts: true,
  34. returns: true,
  35. }
  36. return instructionSet
  37. }

NewHomesteadInstructionSet

  1. // NewHomesteadInstructionSet returns the frontier and homestead
  2. // instructions that can be executed during the homestead phase.
  3. func NewHomesteadInstructionSet() [256]operation {
  4. instructionSet := NewFrontierInstructionSet()
  5. instructionSet[DELEGATECALL] = operation{
  6. execute: opDelegateCall,
  7. gasCost: gasDelegateCall,
  8. validateStack: makeStackFunc(6, 1),
  9. memorySize: memoryDelegateCall,
  10. valid: true,
  11. returns: true,
  12. }
  13. return instructionSet
  14. }

instruction.go

因为指令很多,所以不一一列出来, 只列举几个例子. 虽然组合起来的功能可以很复杂,但是单个指令来说,还是比较直观的.

  1. func opPc(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
  2. stack.push(evm.interpreter.intPool.get().SetUint64(*pc))
  3. return nil, nil
  4. }
  5. func opMsize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
  6. stack.push(evm.interpreter.intPool.get().SetInt64(int64(memory.Len())))
  7. return nil, nil
  8. }

gas_table.go

gas_table返回了各种指令消耗的gas的函数 这个函数的返回值基本上只有errGasUintOverflow 整数溢出的错误.

  1. func gasBalance(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
  2. return gt.Balance, nil
  3. }
  4. func gasExtCodeSize(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
  5. return gt.ExtcodeSize, nil
  6. }
  7. func gasSLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
  8. return gt.SLoad, nil
  9. }
  10. func gasExp(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
  11. expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8)
  12. var (
  13. gas = expByteLen * gt.ExpByte // no overflow check required. Max is 256 * ExpByte gas
  14. overflow bool
  15. )
  16. if gas, overflow = math.SafeAdd(gas, GasSlowStep); overflow {
  17. return 0, errGasUintOverflow
  18. }
  19. return gas, nil
  20. }

interpreter.go 解释器

数据结构

  1. // Config are the configuration options for the Interpreter
  2. type Config struct {
  3. // Debug enabled debugging Interpreter options
  4. Debug bool
  5. // EnableJit enabled the JIT VM
  6. EnableJit bool
  7. // ForceJit forces the JIT VM
  8. ForceJit bool
  9. // Tracer is the op code logger
  10. Tracer Tracer
  11. // NoRecursion disabled Interpreter call, callcode,
  12. // delegate call and create.
  13. NoRecursion bool
  14. // Disable gas metering
  15. DisableGasMetering bool
  16. // Enable recording of SHA3/keccak preimages
  17. EnablePreimageRecording bool
  18. // JumpTable contains the EVM instruction table. This
  19. // may be left uninitialised and will be set to the default
  20. // table.
  21. JumpTable [256]operation
  22. }
  23. // Interpreter is used to run Ethereum based contracts and will utilise the
  24. // passed evmironment to query external sources for state information.
  25. // The Interpreter will run the byte code VM or JIT VM based on the passed
  26. // configuration.
  27. type Interpreter struct {
  28. evm *EVM
  29. cfg Config
  30. gasTable params.GasTable // 标识了很多操作的Gas价格
  31. intPool *intPool
  32. readOnly bool // Whether to throw on stateful modifications
  33. returnData []byte // Last CALL's return data for subsequent reuse 最后一个函数的返回值
  34. }

构造函数

  1. // NewInterpreter returns a new instance of the Interpreter.
  2. func NewInterpreter(evm *EVM, cfg Config) *Interpreter {
  3. // We use the STOP instruction whether to see
  4. // the jump table was initialised. If it was not
  5. // we'll set the default jump table.
  6. // 用一个STOP指令测试JumpTable是否已经被初始化了, 如果没有被初始化,那么设置为默认值
  7. if !cfg.JumpTable[STOP].valid {
  8. switch {
  9. case evm.ChainConfig().IsByzantium(evm.BlockNumber):
  10. cfg.JumpTable = byzantiumInstructionSet
  11. case evm.ChainConfig().IsHomestead(evm.BlockNumber):
  12. cfg.JumpTable = homesteadInstructionSet
  13. default:
  14. cfg.JumpTable = frontierInstructionSet
  15. }
  16. }
  17. return &Interpreter{
  18. evm: evm,
  19. cfg: cfg,
  20. gasTable: evm.ChainConfig().GasTable(evm.BlockNumber),
  21. intPool: newIntPool(),
  22. }
  23. }

解释器一共就两个方法enforceRestrictions方法和Run方法.

  1. func (in *Interpreter) enforceRestrictions(op OpCode, operation operation, stack *Stack) error {
  2. if in.evm.chainRules.IsByzantium {
  3. if in.readOnly {
  4. // If the interpreter is operating in readonly mode, make sure no
  5. // state-modifying operation is performed. The 3rd stack item
  6. // for a call operation is the value. Transferring value from one
  7. // account to the others means the state is modified and should also
  8. // return with an error.
  9. if operation.writes || (op == CALL && stack.Back(2).BitLen() > 0) {
  10. return errWriteProtection
  11. }
  12. }
  13. }
  14. return nil
  15. }
  16. // Run loops and evaluates the contract's code with the given input data and returns
  17. // the return byte-slice and an error if one occurred.
  18. // 用给定的入参循环执行合约的代码,并返回返回的字节片段,如果发生错误则返回错误。
  19. // It's important to note that any errors returned by the interpreter should be
  20. // considered a revert-and-consume-all-gas operation. No error specific checks
  21. // should be handled to reduce complexity and errors further down the in.
  22. // 重要的是要注意,解释器返回的任何错误都会消耗全部gas。 为了减少复杂性,没有特别的错误处理流程。
  23. func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret []byte, err error) {
  24. // Increment the call depth which is restricted to 1024
  25. in.evm.depth++
  26. defer func() { in.evm.depth-- }()
  27. // Reset the previous call's return data. It's unimportant to preserve the old buffer
  28. // as every returning call will return new data anyway.
  29. in.returnData = nil
  30. // Don't bother with the execution if there's no code.
  31. if len(contract.Code) == 0 {
  32. return nil, nil
  33. }
  34. codehash := contract.CodeHash // codehash is used when doing jump dest caching
  35. if codehash == (common.Hash{}) {
  36. codehash = crypto.Keccak256Hash(contract.Code)
  37. }
  38. var (
  39. op OpCode // current opcode
  40. mem = NewMemory() // bound memory
  41. stack = newstack() // local stack
  42. // For optimisation reason we're using uint64 as the program counter.
  43. // It's theoretically possible to go above 2^64. The YP defines the PC
  44. // to be uint256. Practically much less so feasible.
  45. pc = uint64(0) // program counter
  46. cost uint64
  47. // copies used by tracer
  48. stackCopy = newstack() // stackCopy needed for Tracer since stack is mutated by 63/64 gas rule
  49. pcCopy uint64 // needed for the deferred Tracer
  50. gasCopy uint64 // for Tracer to log gas remaining before execution
  51. logged bool // deferred Tracer should ignore already logged steps
  52. )
  53. contract.Input = input
  54. defer func() {
  55. if err != nil && !logged && in.cfg.Debug {
  56. in.cfg.Tracer.CaptureState(in.evm, pcCopy, op, gasCopy, cost, mem, stackCopy, contract, in.evm.depth, err)
  57. }
  58. }()
  59. // The Interpreter main run loop (contextual). This loop runs until either an
  60. // explicit STOP, RETURN or SELFDESTRUCT is executed, an error occurred during
  61. // the execution of one of the operations or until the done flag is set by the
  62. // parent context.
  63. // 解释器的主要循环, 直到遇到STOP,RETURN,SELFDESTRUCT指令被执行,或者是遇到任意错误,或者说done 标志被父context设置。
  64. for atomic.LoadInt32(&in.evm.abort) == 0 {
  65. // Get the memory location of pc
  66. // 难道下一个需要执行的指令
  67. op = contract.GetOp(pc)
  68. if in.cfg.Debug {
  69. logged = false
  70. pcCopy = uint64(pc)
  71. gasCopy = uint64(contract.Gas)
  72. stackCopy = newstack()
  73. for _, val := range stack.data {
  74. stackCopy.push(val)
  75. }
  76. }
  77. // get the operation from the jump table matching the opcode
  78. // 通过JumpTable拿到对应的operation
  79. operation := in.cfg.JumpTable[op]
  80. // 这里检查了只读模式下面不能执行writes指令
  81. // staticCall的情况下会设置为readonly模式
  82. if err := in.enforceRestrictions(op, operation, stack); err != nil {
  83. return nil, err
  84. }
  85. // if the op is invalid abort the process and return an error
  86. if !operation.valid { //检查指令是否非法
  87. return nil, fmt.Errorf("invalid opcode 0x%x", int(op))
  88. }
  89. // validate the stack and make sure there enough stack items available
  90. // to perform the operation
  91. // 检查是否有足够的堆栈空间。 包括入栈和出栈
  92. if err := operation.validateStack(stack); err != nil {
  93. return nil, err
  94. }
  95. var memorySize uint64
  96. // calculate the new memory size and expand the memory to fit
  97. // the operation
  98. if operation.memorySize != nil { // 计算内存使用量,需要收费
  99. memSize, overflow := bigUint64(operation.memorySize(stack))
  100. if overflow {
  101. return nil, errGasUintOverflow
  102. }
  103. // memory is expanded in words of 32 bytes. Gas
  104. // is also calculated in words.
  105. if memorySize, overflow = math.SafeMul(toWordSize(memSize), 32); overflow {
  106. return nil, errGasUintOverflow
  107. }
  108. }
  109. if !in.cfg.DisableGasMetering { //这个参数在本地模拟执行的时候比较有用,可以不消耗或者检查GAS执行交易并得到返回结果
  110. // consume the gas and return an error if not enough gas is available.
  111. // cost is explicitly set so that the capture state defer method cas get the proper cost
  112. // 计算gas的Cost 并使用,如果不够,就返回OutOfGas错误。
  113. cost, err = operation.gasCost(in.gasTable, in.evm, contract, stack, mem, memorySize)
  114. if err != nil || !contract.UseGas(cost) {
  115. return nil, ErrOutOfGas
  116. }
  117. }
  118. if memorySize > 0 { //扩大内存范围
  119. mem.Resize(memorySize)
  120. }
  121. if in.cfg.Debug {
  122. in.cfg.Tracer.CaptureState(in.evm, pc, op, gasCopy, cost, mem, stackCopy, contract, in.evm.depth, err)
  123. logged = true
  124. }
  125. // execute the operation
  126. // 执行命令
  127. res, err := operation.execute(&pc, in.evm, contract, mem, stack)
  128. // verifyPool is a build flag. Pool verification makes sure the integrity
  129. // of the integer pool by comparing values to a default value.
  130. if verifyPool {
  131. verifyIntegerPool(in.intPool)
  132. }
  133. // if the operation clears the return data (e.g. it has returning data)
  134. // set the last return to the result of the operation.
  135. if operation.returns { //如果有返回值,那么就设置返回值。 注意只有最后一个返回有效果。
  136. in.returnData = res
  137. }
  138. switch {
  139. case err != nil:
  140. return nil, err
  141. case operation.reverts:
  142. return res, errExecutionReverted
  143. case operation.halts:
  144. return res, nil
  145. case !operation.jumps:
  146. pc++
  147. }
  148. }
  149. return nil, nil
  150. }