ETH 源码分析
入口函数:ransitionDb()
func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { // 首先检查此消息是否满足之前的所有共识规则 // 应用消息。 规则包括这些条款 // // 1. 消息调用者的随机数是正确的 // 2. 调用方有足够的余额来支付交易费用(gaslimit * gasprice) // 3. 所需的 gas 数量在区块中是可用的 // 4. 购买的 gas 足以覆盖内部使用 // 5. 计算本征气体时没有溢出 // 6. caller 有足够的余额来支付 **topmost** 调用的资产转移 // 检查条款 1-3,如果一切正确就检测gas if err := st.preCheck(); err != nil { return nil, err } if st.evm.Config.Debug { st.evm.Config.Tracer.CaptureTxStart(st.initialGas) defer func() { st.evm.Config.Tracer.CaptureTxEnd(st.gas) }() } var ( msg = st.msg sender = vm.AccountRef(msg.From()) rules = st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber, st.evm.Context.Random != nil) contractCreation = msg.To() == nil ) // Check clauses 4-5, subtract intrinsic gas if everything is correct // 检查第 4-5 条,如果一切正确则减去 内部 gas gas, err := IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, rules.IsHomestead, rules.IsIstanbul) if err != nil { return nil, err } if st.gas < gas { return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gas, gas) } st.gas -= gas // Check clause 6 // 检查第 6 条 if msg.Value().Sign() > 0 && !st.evm.Context.CanTransfer(st.state, msg.From(), msg.Value()) { return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From().Hex()) } // Execute the preparatory steps for state transition which includes: // - prepare accessList(post-berlin) // - reset transient storage(eip 1153) st.state.Prepare(rules, msg.From(), st.evm.Context.Coinbase, msg.To(), vm.ActivePrecompiles(rules), msg.AccessList()) var ( ret []byte vmerr error // vm errors do not effect consensus and are therefore not assigned to err ) 当以太坊的交易中to地址为nil时, 意味着部署合约, 那么就会调用evm.Create方法。 否则调用了evm.Call方法。 也就是说分析以太坊虚拟机源码时, 只要从这两个函数作为入口即可。 if contractCreation { ret, _, st.gas, vmerr = st.evm.Create(sender, st.data, st.gas, st.value) } else { // Increment the nonce for the next transaction st.state.SetNonce(msg.From(), st.state.GetNonce(sender.Address())+1) ret, st.gas, vmerr = st.evm.Call(sender, st.to(), st.data, st.gas, st.value) } if !rules.IsLondon { // Before EIP-3529: refunds were capped to gasUsed / 2 st.refundGas(params.RefundQuotient) } else { // After EIP-3529: refunds are capped to gasUsed / 5 st.refundGas(params.RefundQuotientEIP3529) } effectiveTip := st.gasPrice if rules.IsLondon { effectiveTip = cmath.BigMin(st.gasTipCap, new(big.Int).Sub(st.gasFeeCap, st.evm.Context.BaseFee)) } if st.evm.Config.NoBaseFee && st.gasFeeCap.Sign() == 0 && st.gasTipCap.Sign() == 0 { // Skip fee payment when NoBaseFee is set and the fee fields // are 0. This avoids a negative effectiveTip being applied to // the coinbase when simulating calls. } else { fee := new(big.Int).SetUint64(st.gasUsed()) fee.Mul(fee, effectiveTip) st.state.AddBalance(st.evm.Context.Coinbase, fee) } return &ExecutionResult{ UsedGas: st.gasUsed(), Err: vmerr, ReturnData: ret, }, nil }
标签:evm,nil,rules,gas,st,源码,msg,eth From: https://www.cnblogs.com/Sunbreaker/p/17036281.html