github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/core/vm/interpreter.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 12:09:35</date>
    10  //</624342622231597056>
    11  
    12  
    13  package vm
    14  
    15  import (
    16  	"fmt"
    17  	"sync/atomic"
    18  
    19  	"github.com/ethereum/go-ethereum/common/math"
    20  	"github.com/ethereum/go-ethereum/params"
    21  )
    22  
    23  //config是解释器的配置选项
    24  type Config struct {
    25  //启用调试的调试解释器选项
    26  	Debug bool
    27  //跟踪程序是操作代码记录器
    28  	Tracer Tracer
    29  //无加密禁用的解释程序调用,调用代码,
    30  //委派呼叫并创建。
    31  	NoRecursion bool
    32  //启用sha3/keccak preimages的录制
    33  	EnablePreimageRecording bool
    34  //JumpTable包含EVM指令表。这个
    35  //可能未初始化,并将设置为默认值
    36  //表。
    37  	JumpTable [256]operation
    38  }
    39  
    40  //解释器用于运行基于以太坊的合同,并将使用
    41  //已传递环境以查询外部源以获取状态信息。
    42  //解释器将根据传递的
    43  //配置。
    44  type Interpreter interface {
    45  //运行循环并使用给定的输入数据评估契约的代码并返回
    46  //返回字节切片,如果出现错误,则返回一个错误。
    47  	Run(contract *Contract, input []byte) ([]byte, error)
    48  //canrun告诉作为参数传递的契约是否可以
    49  //由当前解释器运行。这意味着
    50  //呼叫方可以执行以下操作:
    51  //
    52  //'Gangang'
    53  //对于u,解释器:=测距解释器
    54  //if explorer.canrun(contract.code)
    55  //解释器.run(contract.code,input)
    56  //}
    57  //}
    58  //` `
    59  	CanRun([]byte) bool
    60  //如果解释器处于只读模式,is read only将报告。
    61  	IsReadOnly() bool
    62  //setreadonly在解释器中设置(或取消设置)只读模式。
    63  	SetReadOnly(bool)
    64  }
    65  
    66  //evm interpreter表示evm解释器
    67  type EVMInterpreter struct {
    68  	evm      *EVM
    69  	cfg      Config
    70  	gasTable params.GasTable
    71  	intPool  *intPool
    72  
    73  readOnly   bool   //是否进行状态修改
    74  returnData []byte //最后一次调用的返回数据供后续重用
    75  }
    76  
    77  //NewEvminterPreter返回解释器的新实例。
    78  func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
    79  //我们使用停止指令是否看到
    80  //跳转表已初始化。如果不是
    81  //我们将设置默认跳转表。
    82  	if !cfg.JumpTable[STOP].valid {
    83  		switch {
    84  		case evm.ChainConfig().IsConstantinople(evm.BlockNumber):
    85  			cfg.JumpTable = constantinopleInstructionSet
    86  		case evm.ChainConfig().IsByzantium(evm.BlockNumber):
    87  			cfg.JumpTable = byzantiumInstructionSet
    88  		case evm.ChainConfig().IsHomestead(evm.BlockNumber):
    89  			cfg.JumpTable = homesteadInstructionSet
    90  		default:
    91  			cfg.JumpTable = frontierInstructionSet
    92  		}
    93  	}
    94  
    95  	return &EVMInterpreter{
    96  		evm:      evm,
    97  		cfg:      cfg,
    98  		gasTable: evm.ChainConfig().GasTable(evm.BlockNumber),
    99  	}
   100  }
   101  
   102  func (in *EVMInterpreter) enforceRestrictions(op OpCode, operation operation, stack *Stack) error {
   103  	if in.evm.chainRules.IsByzantium {
   104  		if in.readOnly {
   105  //如果解释器在只读模式下工作,请确保否
   106  //执行状态修改操作。第三个堆栈项
   107  //对于一个调用操作来说是值。从一个转移价值
   108  //对其他人的帐户意味着状态被修改,并且应该
   109  //返回时出错。
   110  			if operation.writes || (op == CALL && stack.Back(2).BitLen() > 0) {
   111  				return errWriteProtection
   112  			}
   113  		}
   114  	}
   115  	return nil
   116  }
   117  
   118  //运行循环并使用给定的输入数据评估契约的代码并返回
   119  //返回字节切片,如果出现错误,则返回一个错误。
   120  //
   121  //需要注意的是,解释程序返回的任何错误都应该
   122  //被认为是一种还原和消耗除
   123  //errExecutionReverted,这意味着还原并保留气体。
   124  func (in *EVMInterpreter) Run(contract *Contract, input []byte) (ret []byte, err error) {
   125  	if in.intPool == nil {
   126  		in.intPool = poolOfIntPools.get()
   127  		defer func() {
   128  			poolOfIntPools.put(in.intPool)
   129  			in.intPool = nil
   130  		}()
   131  	}
   132  
   133  //增加限制为1024的调用深度
   134  	in.evm.depth++
   135  	defer func() { in.evm.depth-- }()
   136  
   137  //重置上一个呼叫的返回数据。保留旧的缓冲区并不重要
   138  //因为每次回电都会返回新的数据。
   139  	in.returnData = nil
   140  
   141  //如果没有代码,就不必费心执行。
   142  	if len(contract.Code) == 0 {
   143  		return nil, nil
   144  	}
   145  
   146  	var (
   147  op    OpCode        //当前操作码
   148  mem   = NewMemory() //绑定内存
   149  stack = newstack()  //本地栈
   150  //为了优化,我们使用uint64作为程序计数器。
   151  //理论上可以超过2^64。YP定义PC
   152  //为UIT2525。实际上不那么可行。
   153  pc   = uint64(0) //程序计数器
   154  		cost uint64
   155  //追踪器使用的副本
   156  pcCopy  uint64 //延期追踪器需要
   157  gasCopy uint64 //用于示踪剂记录执行前的剩余气体
   158  logged  bool   //延迟跟踪程序应忽略已记录的步骤
   159  	)
   160  	contract.Input = input
   161  
   162  //在执行停止时将堆栈作为int池回收
   163  	defer func() { in.intPool.put(stack.data...) }()
   164  
   165  	if in.cfg.Debug {
   166  		defer func() {
   167  			if err != nil {
   168  				if !logged {
   169  					in.cfg.Tracer.CaptureState(in.evm, pcCopy, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err)
   170  				} else {
   171  					in.cfg.Tracer.CaptureFault(in.evm, pcCopy, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err)
   172  				}
   173  			}
   174  		}()
   175  	}
   176  //解释器主运行循环(上下文)。此循环运行到
   177  //执行显式停止、返回或自毁函数,期间发生错误
   178  //执行一个操作,或直到完成标志由
   179  //父上下文。
   180  	for atomic.LoadInt32(&in.evm.abort) == 0 {
   181  		if in.cfg.Debug {
   182  //捕获执行前的值以进行跟踪。
   183  			logged, pcCopy, gasCopy = false, pc, contract.Gas
   184  		}
   185  
   186  //从跳转表中获取操作并验证堆栈以确保
   187  //有足够的堆栈项可用于执行该操作。
   188  		op = contract.GetOp(pc)
   189  		operation := in.cfg.JumpTable[op]
   190  		if !operation.valid {
   191  			return nil, fmt.Errorf("invalid opcode 0x%x", int(op))
   192  		}
   193  		if err := operation.validateStack(stack); err != nil {
   194  			return nil, err
   195  		}
   196  //如果操作有效,则强制执行并写入限制
   197  		if err := in.enforceRestrictions(op, operation, stack); err != nil {
   198  			return nil, err
   199  		}
   200  
   201  		var memorySize uint64
   202  //计算新内存大小并展开内存以适应
   203  //手术
   204  		if operation.memorySize != nil {
   205  			memSize, overflow := bigUint64(operation.memorySize(stack))
   206  			if overflow {
   207  				return nil, errGasUintOverflow
   208  			}
   209  //内存以32字节的字扩展。气体
   210  //也用文字计算。
   211  			if memorySize, overflow = math.SafeMul(toWordSize(memSize), 32); overflow {
   212  				return nil, errGasUintOverflow
   213  			}
   214  		}
   215  //如果没有足够的气体可用,则消耗气体并返回错误。
   216  //明确设置成本,以便捕获状态延迟方法可以获得适当的成本
   217  		cost, err = operation.gasCost(in.gasTable, in.evm, contract, stack, mem, memorySize)
   218  		if err != nil || !contract.UseGas(cost) {
   219  			return nil, ErrOutOfGas
   220  		}
   221  		if memorySize > 0 {
   222  			mem.Resize(memorySize)
   223  		}
   224  
   225  		if in.cfg.Debug {
   226  			in.cfg.Tracer.CaptureState(in.evm, pc, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err)
   227  			logged = true
   228  		}
   229  
   230  //执行操作
   231  		res, err := operation.execute(&pc, in, contract, mem, stack)
   232  //VerifyPool是一个生成标志。池验证确保完整性
   233  //通过将值与默认值进行比较来获得整数池的值。
   234  		if verifyPool {
   235  			verifyIntegerPool(in.intPool)
   236  		}
   237  //如果操作清除返回数据(例如,它有返回数据)
   238  //将最后一个返回设置为操作结果。
   239  		if operation.returns {
   240  			in.returnData = res
   241  		}
   242  
   243  		switch {
   244  		case err != nil:
   245  			return nil, err
   246  		case operation.reverts:
   247  			return res, errExecutionReverted
   248  		case operation.halts:
   249  			return res, nil
   250  		case !operation.jumps:
   251  			pc++
   252  		}
   253  	}
   254  	return nil, nil
   255  }
   256  
   257  //canrun告诉作为参数传递的契约是否可以
   258  //由当前解释器运行。
   259  func (in *EVMInterpreter) CanRun(code []byte) bool {
   260  	return true
   261  }
   262  
   263  //如果解释器处于只读模式,is read only将报告。
   264  func (in *EVMInterpreter) IsReadOnly() bool {
   265  	return in.readOnly
   266  }
   267  
   268  //setreadonly在解释器中设置(或取消设置)只读模式。
   269  func (in *EVMInterpreter) SetReadOnly(ro bool) {
   270  	in.readOnly = ro
   271  }
   272