github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/core/vm/evm.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 19:16:36</date>
    10  //</624450082183319552>
    11  
    12  
    13  package vm
    14  
    15  import (
    16  	"math/big"
    17  	"sync/atomic"
    18  	"time"
    19  
    20  	"github.com/ethereum/go-ethereum/common"
    21  	"github.com/ethereum/go-ethereum/crypto"
    22  	"github.com/ethereum/go-ethereum/params"
    23  )
    24  
    25  //create使用EmptyCodeHash来确保已不允许部署
    26  //已部署的合同地址(在帐户提取之后相关)。
    27  var emptyCodeHash = crypto.Keccak256Hash(nil)
    28  
    29  type (
    30  //cantransferfunc是传递保护函数的签名
    31  	CanTransferFunc func(StateDB, common.Address, *big.Int) bool
    32  //transferFunc是传递函数的签名
    33  	TransferFunc func(StateDB, common.Address, common.Address, *big.Int)
    34  //gethashfunc返回区块链中的第n个区块哈希
    35  //并由blockhash evm op代码使用。
    36  	GetHashFunc func(uint64) common.Hash
    37  )
    38  
    39  //Run运行给定的合同,并负责运行回退到字节码解释器的预编译。
    40  func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, error) {
    41  	if contract.CodeAddr != nil {
    42  		precompiles := PrecompiledContractsHomestead
    43  		if evm.ChainConfig().IsByzantium(evm.BlockNumber) {
    44  			precompiles = PrecompiledContractsByzantium
    45  		}
    46  		if p := precompiles[*contract.CodeAddr]; p != nil {
    47  			return RunPrecompiledContract(p, input, contract)
    48  		}
    49  	}
    50  	for _, interpreter := range evm.interpreters {
    51  		if interpreter.CanRun(contract.Code) {
    52  			if evm.interpreter != interpreter {
    53  //确保解释器指针设置回原处
    54  //返回到当前值。
    55  				defer func(i Interpreter) {
    56  					evm.interpreter = i
    57  				}(evm.interpreter)
    58  				evm.interpreter = interpreter
    59  			}
    60  			return interpreter.Run(contract, input, readOnly)
    61  		}
    62  	}
    63  	return nil, ErrNoCompatibleInterpreter
    64  }
    65  
    66  //上下文为EVM提供辅助信息。一旦提供
    67  //它不应该被修改。
    68  type Context struct {
    69  //CanTransfer返回帐户是否包含
    70  //足够的乙醚转移价值
    71  	CanTransfer CanTransferFunc
    72  //将乙醚从一个帐户转移到另一个帐户
    73  	Transfer TransferFunc
    74  //GetHash返回与n对应的哈希
    75  	GetHash GetHashFunc
    76  
    77  //消息信息
    78  Origin   common.Address //提供源站信息
    79  GasPrice *big.Int       //为Gasprice提供信息
    80  
    81  //阻止信息
    82  Coinbase    common.Address //为CoinBase提供信息
    83  GasLimit    uint64         //Provides information for GASLIMIT
    84  BlockNumber *big.Int       //提供数字信息
    85  Time        *big.Int       //提供时间信息
    86  Difficulty  *big.Int       //为困难提供信息
    87  }
    88  
    89  //EVM是以太坊虚拟机基础对象,它提供
    90  //在给定状态下运行合同所需的工具
    91  //提供的上下文。应该注意的是,任何错误
    92  //通过任何调用生成的应被视为
    93  //恢复状态并消耗所有气体操作,不检查
    94  //应执行特定错误。翻译使
    95  //确保生成的任何错误都被视为错误代码。
    96  //
    97  //EVM不应该被重用,也不是线程安全的。
    98  type EVM struct {
    99  //上下文提供辅助区块链相关信息
   100  	Context
   101  //statedb提供对底层状态的访问
   102  	StateDB StateDB
   103  //深度是当前调用堆栈
   104  	depth int
   105  
   106  //chainconfig包含有关当前链的信息
   107  	chainConfig *params.ChainConfig
   108  //链规则包含当前纪元的链规则
   109  	chainRules params.Rules
   110  //用于初始化的虚拟机配置选项
   111  //EVM。
   112  	vmConfig Config
   113  //全局(到此上下文)以太坊虚拟机
   114  //在整个Tx执行过程中使用。
   115  	interpreters []Interpreter
   116  	interpreter  Interpreter
   117  //abort用于中止EVM调用操作
   118  //注:必须按原子顺序设置
   119  	abort int32
   120  //callgastemp保留当前呼叫可用的气体。这是需要的,因为
   121  //根据63/64规则和更高版本,可用气体在GasCall*中计算。
   122  //在opcall*中应用。
   123  	callGasTemp uint64
   124  }
   125  
   126  //new evm返回新的evm。返回的EVM不是线程安全的,应该
   127  //只能使用一次。
   128  func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmConfig Config) *EVM {
   129  	evm := &EVM{
   130  		Context:      ctx,
   131  		StateDB:      statedb,
   132  		vmConfig:     vmConfig,
   133  		chainConfig:  chainConfig,
   134  		chainRules:   chainConfig.Rules(ctx.BlockNumber),
   135  		interpreters: make([]Interpreter, 0, 1),
   136  	}
   137  
   138  	if chainConfig.IsEWASM(ctx.BlockNumber) {
   139  //由EVM-C和货车PRS实施。
   140  //如果vmconfig.ewasminterper!=“{”
   141  //extIntopts:=strings.split(vmconfig.ewasInterpreter,“:”)
   142  //路径:=extintopts[0]
   143  //选项:=[]字符串
   144  //如果len(extintopts)>1
   145  //选项=extintopts[1..]
   146  //}
   147  //evm.interpreters=append(evm.interpreters,newevmvcinterpreter(evm,vmconfig,options))。
   148  //}否则{
   149  //evm.interpreters=append(evm.interpreters,newewasInterpreter(evm,vmconfig))。
   150  //}
   151  		panic("No supported ewasm interpreter yet.")
   152  	}
   153  
   154  //vmconfig.evminterpreter将由evm-c使用,此处不检查
   155  //因为我们总是希望将内置的EVM作为故障转移选项。
   156  	evm.interpreters = append(evm.interpreters, NewEVMInterpreter(evm, vmConfig))
   157  	evm.interpreter = evm.interpreters[0]
   158  
   159  	return evm
   160  }
   161  
   162  //取消取消任何正在运行的EVM操作。这可以同时调用,并且
   163  //多次打电话是安全的。
   164  func (evm *EVM) Cancel() {
   165  	atomic.StoreInt32(&evm.abort, 1)
   166  }
   167  
   168  //解释器返回当前解释器
   169  func (evm *EVM) Interpreter() Interpreter {
   170  	return evm.interpreter
   171  }
   172  
   173  //调用执行与给定输入为的addr关联的协定
   174  //参数。它还处理任何必要的价值转移,并采取
   175  //创建帐户和在
   176  //执行错误或值传输失败。
   177  func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) {
   178  	if evm.vmConfig.NoRecursion && evm.depth > 0 {
   179  		return nil, gas, nil
   180  	}
   181  
   182  //如果我们试图执行超过调用深度限制,则失败
   183  	if evm.depth > int(params.CallCreateDepth) {
   184  		return nil, gas, ErrDepth
   185  	}
   186  //如果我们试图转移的余额超过可用余额,则失败
   187  	if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) {
   188  		return nil, gas, ErrInsufficientBalance
   189  	}
   190  
   191  	var (
   192  		to       = AccountRef(addr)
   193  		snapshot = evm.StateDB.Snapshot()
   194  	)
   195  	if !evm.StateDB.Exist(addr) {
   196  		precompiles := PrecompiledContractsHomestead
   197  		if evm.ChainConfig().IsByzantium(evm.BlockNumber) {
   198  			precompiles = PrecompiledContractsByzantium
   199  		}
   200  		if precompiles[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.Sign() == 0 {
   201  //调用一个不存在的帐户,不要做任何事情,只需ping跟踪程序
   202  			if evm.vmConfig.Debug && evm.depth == 0 {
   203  				evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value)
   204  				evm.vmConfig.Tracer.CaptureEnd(ret, 0, 0, nil)
   205  			}
   206  			return nil, gas, nil
   207  		}
   208  		evm.StateDB.CreateAccount(addr)
   209  	}
   210  	evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value)
   211  //初始化新合同并设置EVM要使用的代码。
   212  //契约只是这个执行上下文的作用域环境。
   213  	contract := NewContract(caller, to, value, gas)
   214  	contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
   215  
   216  //即使帐户没有代码,我们也需要继续,因为它可能是预编译的
   217  	start := time.Now()
   218  
   219  //在调试模式下捕获跟踪程序开始/结束事件
   220  	if evm.vmConfig.Debug && evm.depth == 0 {
   221  		evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value)
   222  
   223  defer func() { //参数的延迟评估
   224  			evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err)
   225  		}()
   226  	}
   227  	ret, err = run(evm, contract, input, false)
   228  
   229  //当EVM返回错误或设置创建代码时
   230  //在上面,我们返回快照并消耗所有剩余的气体。另外
   231  //当我们在宅基地时,这也算是代码存储气体错误。
   232  	if err != nil {
   233  		evm.StateDB.RevertToSnapshot(snapshot)
   234  		if err != errExecutionReverted {
   235  			contract.UseGas(contract.Gas)
   236  		}
   237  	}
   238  	return ret, contract.Gas, err
   239  }
   240  
   241  //callcode使用给定的输入执行与addr关联的协定
   242  //作为参数。它还处理任何必要的价值转移,并采取
   243  //创建帐户和在
   244  //执行错误或值传输失败。
   245  //
   246  //callcode与call的区别在于它执行给定的地址'
   247  //以调用方为上下文的代码。
   248  func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) {
   249  	if evm.vmConfig.NoRecursion && evm.depth > 0 {
   250  		return nil, gas, nil
   251  	}
   252  
   253  //如果我们试图执行超过调用深度限制,则失败
   254  	if evm.depth > int(params.CallCreateDepth) {
   255  		return nil, gas, ErrDepth
   256  	}
   257  //如果我们试图转移的余额超过可用余额,则失败
   258  	if !evm.CanTransfer(evm.StateDB, caller.Address(), value) {
   259  		return nil, gas, ErrInsufficientBalance
   260  	}
   261  
   262  	var (
   263  		snapshot = evm.StateDB.Snapshot()
   264  		to       = AccountRef(caller.Address())
   265  	)
   266  //初始化新合同并设置
   267  //EVM。合同是此执行上下文的作用域环境
   268  //只有。
   269  	contract := NewContract(caller, to, value, gas)
   270  	contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
   271  
   272  	ret, err = run(evm, contract, input, false)
   273  	if err != nil {
   274  		evm.StateDB.RevertToSnapshot(snapshot)
   275  		if err != errExecutionReverted {
   276  			contract.UseGas(contract.Gas)
   277  		}
   278  	}
   279  	return ret, contract.Gas, err
   280  }
   281  
   282  //DelegateCall执行与给定输入的addr关联的协定
   283  //作为参数。如果发生执行错误,它将反转状态。
   284  //
   285  //delegateCall与callcode的区别在于它执行给定的地址'
   286  //以调用者为上下文的代码,调用者被设置为调用者的调用者。
   287  func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) {
   288  	if evm.vmConfig.NoRecursion && evm.depth > 0 {
   289  		return nil, gas, nil
   290  	}
   291  //如果我们试图执行超过调用深度限制,则失败
   292  	if evm.depth > int(params.CallCreateDepth) {
   293  		return nil, gas, ErrDepth
   294  	}
   295  
   296  	var (
   297  		snapshot = evm.StateDB.Snapshot()
   298  		to       = AccountRef(caller.Address())
   299  	)
   300  
   301  //初始化新合同并使委托值初始化
   302  	contract := NewContract(caller, to, nil, gas).AsDelegate()
   303  	contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
   304  
   305  	ret, err = run(evm, contract, input, false)
   306  	if err != nil {
   307  		evm.StateDB.RevertToSnapshot(snapshot)
   308  		if err != errExecutionReverted {
   309  			contract.UseGas(contract.Gas)
   310  		}
   311  	}
   312  	return ret, contract.Gas, err
   313  }
   314  
   315  //staticCall使用给定的输入执行与addr关联的协定
   316  //作为参数,同时不允许在调用期间对状态进行任何修改。
   317  //试图执行此类修改的操作码将导致异常
   318  //而不是执行修改。
   319  func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) {
   320  	if evm.vmConfig.NoRecursion && evm.depth > 0 {
   321  		return nil, gas, nil
   322  	}
   323  //如果我们试图执行超过调用深度限制,则失败
   324  	if evm.depth > int(params.CallCreateDepth) {
   325  		return nil, gas, ErrDepth
   326  	}
   327  
   328  	var (
   329  		to       = AccountRef(addr)
   330  		snapshot = evm.StateDB.Snapshot()
   331  	)
   332  //初始化新合同并设置
   333  //EVM。合同是此执行上下文的作用域环境
   334  //只有。
   335  	contract := NewContract(caller, to, new(big.Int), gas)
   336  	contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
   337  
   338  //我们在这里做一个零的加法平衡,只是为了触发一个触摸。
   339  //在拜占庭时代,所有空的东西都不见了。
   340  //但是,在其他网络、测试和潜力方面是否正确以及重要?
   341  //未来情景
   342  	evm.StateDB.AddBalance(addr, bigZero)
   343  
   344  //当EVM返回错误或设置创建代码时
   345  //在上面,我们返回快照并消耗所有剩余的气体。另外
   346  //当我们在宅基地时,这也算是代码存储气体错误。
   347  	ret, err = run(evm, contract, input, true)
   348  	if err != nil {
   349  		evm.StateDB.RevertToSnapshot(snapshot)
   350  		if err != errExecutionReverted {
   351  			contract.UseGas(contract.Gas)
   352  		}
   353  	}
   354  	return ret, contract.Gas, err
   355  }
   356  
   357  type codeAndHash struct {
   358  	code []byte
   359  	hash common.Hash
   360  }
   361  
   362  func (c *codeAndHash) Hash() common.Hash {
   363  	if c.hash == (common.Hash{}) {
   364  		c.hash = crypto.Keccak256Hash(c.code)
   365  	}
   366  	return c.hash
   367  }
   368  
   369  //创建使用代码作为部署代码创建新合同。
   370  func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, value *big.Int, address common.Address) ([]byte, common.Address, uint64, error) {
   371  //深度检查执行。如果我们试图执行上面的
   372  //极限。
   373  	if evm.depth > int(params.CallCreateDepth) {
   374  		return nil, common.Address{}, gas, ErrDepth
   375  	}
   376  	if !evm.CanTransfer(evm.StateDB, caller.Address(), value) {
   377  		return nil, common.Address{}, gas, ErrInsufficientBalance
   378  	}
   379  	nonce := evm.StateDB.GetNonce(caller.Address())
   380  	evm.StateDB.SetNonce(caller.Address(), nonce+1)
   381  
   382  //确保指定地址没有现有合同
   383  	contractHash := evm.StateDB.GetCodeHash(address)
   384  	if evm.StateDB.GetNonce(address) != 0 || (contractHash != (common.Hash{}) && contractHash != emptyCodeHash) {
   385  		return nil, common.Address{}, 0, ErrContractAddressCollision
   386  	}
   387  //在该州创建新帐户
   388  	snapshot := evm.StateDB.Snapshot()
   389  	evm.StateDB.CreateAccount(address)
   390  	if evm.ChainConfig().IsEIP158(evm.BlockNumber) {
   391  		evm.StateDB.SetNonce(address, 1)
   392  	}
   393  	evm.Transfer(evm.StateDB, caller.Address(), address, value)
   394  
   395  //初始化新合同并设置
   396  //EVM。合同是此执行上下文的作用域环境
   397  //只有。
   398  	contract := NewContract(caller, AccountRef(address), value, gas)
   399  	contract.SetCodeOptionalHash(&address, codeAndHash)
   400  
   401  	if evm.vmConfig.NoRecursion && evm.depth > 0 {
   402  		return nil, address, gas, nil
   403  	}
   404  
   405  	if evm.vmConfig.Debug && evm.depth == 0 {
   406  		evm.vmConfig.Tracer.CaptureStart(caller.Address(), address, true, codeAndHash.code, gas, value)
   407  	}
   408  	start := time.Now()
   409  
   410  	ret, err := run(evm, contract, nil, false)
   411  
   412  //检查是否超过了最大代码大小
   413  	maxCodeSizeExceeded := evm.ChainConfig().IsEIP158(evm.BlockNumber) && len(ret) > params.MaxCodeSize
   414  //如果合同创建成功运行且未返回错误
   415  //计算存储代码所需的气体。如果代码不能
   416  //因气量不足而储存,设置错误并处理
   417  //通过下面的错误检查条件。
   418  	if err == nil && !maxCodeSizeExceeded {
   419  		createDataGas := uint64(len(ret)) * params.CreateDataGas
   420  		if contract.UseGas(createDataGas) {
   421  			evm.StateDB.SetCode(address, ret)
   422  		} else {
   423  			err = ErrCodeStoreOutOfGas
   424  		}
   425  	}
   426  
   427  //当EVM返回错误或设置创建代码时
   428  //在上面,我们返回快照并消耗所有剩余的气体。另外
   429  //当我们在宅基地时,这也算是代码存储气体错误。
   430  	if maxCodeSizeExceeded || (err != nil && (evm.ChainConfig().IsHomestead(evm.BlockNumber) || err != ErrCodeStoreOutOfGas)) {
   431  		evm.StateDB.RevertToSnapshot(snapshot)
   432  		if err != errExecutionReverted {
   433  			contract.UseGas(contract.Gas)
   434  		}
   435  	}
   436  //如果合同代码大小超过最大值而错误仍然为空,则分配错误。
   437  	if maxCodeSizeExceeded && err == nil {
   438  		err = errMaxCodeSizeExceeded
   439  	}
   440  	if evm.vmConfig.Debug && evm.depth == 0 {
   441  		evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err)
   442  	}
   443  	return ret, address, contract.Gas, err
   444  
   445  }
   446  
   447  //创建使用代码作为部署代码创建新合同。
   448  func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
   449  	contractAddr = crypto.CreateAddress(caller.Address(), evm.StateDB.GetNonce(caller.Address()))
   450  	return evm.create(caller, &codeAndHash{code: code}, gas, value, contractAddr)
   451  }
   452  
   453  //Create2使用代码作为部署代码创建新合同。
   454  //
   455  //create2与create的区别是create2使用sha3(0xff++msg.sender++salt++sha3(init_code))[12:]
   456  //而不是通常的发送者和nonce散列作为合同初始化的地址。
   457  func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *big.Int, salt *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
   458  	codeAndHash := &codeAndHash{code: code}
   459  	contractAddr = crypto.CreateAddress2(caller.Address(), common.BigToHash(salt), codeAndHash.Hash().Bytes())
   460  	return evm.create(caller, codeAndHash, gas, endowment, contractAddr)
   461  }
   462  
   463  //chainconfig返回环境的链配置
   464  func (evm *EVM) ChainConfig() *params.ChainConfig { return evm.chainConfig }
   465