github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/core/state_transition.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:35</date> 10 //</624450080660787200> 11 12 13 package core 14 15 import ( 16 "errors" 17 "math" 18 "math/big" 19 20 "github.com/ethereum/go-ethereum/common" 21 "github.com/ethereum/go-ethereum/core/vm" 22 "github.com/ethereum/go-ethereum/log" 23 "github.com/ethereum/go-ethereum/params" 24 ) 25 26 var ( 27 errInsufficientBalanceForGas = errors.New("insufficient balance to pay for gas") 28 ) 29 30 /* 31 状态转换模型 32 33 状态转换是将事务应用于当前世界状态时所做的更改。 34 状态转换模型完成了所有必要的工作,以计算出有效的新状态根。 35 36 1)非紧急处理 37 2)预付费煤气 38 3)如果收件人是\0*32,则创建新的状态对象 39 4)价值转移 40 ==如果合同创建== 41 4a)尝试运行事务数据 42 4b)如果有效,将结果用作新状态对象的代码 43 =结束== 44 5)运行脚本部分 45 6)派生新状态根 46 **/ 47 48 type StateTransition struct { 49 gp *GasPool 50 msg Message 51 gas uint64 52 gasPrice *big.Int 53 initialGas uint64 54 value *big.Int 55 data []byte 56 state vm.StateDB 57 evm *vm.EVM 58 } 59 60 //消息表示发送到合同的消息。 61 type Message interface { 62 From() common.Address 63 //fromfrontier()(common.address,错误) 64 To() *common.Address 65 66 GasPrice() *big.Int 67 Gas() uint64 68 Value() *big.Int 69 70 Nonce() uint64 71 CheckNonce() bool 72 Data() []byte 73 } 74 75 //IntrinsicGas用给定的数据计算消息的“固有气体”。 76 func IntrinsicGas(data []byte, contractCreation, homestead bool) (uint64, error) { 77 //设置原始交易的起始气体 78 var gas uint64 79 if contractCreation && homestead { 80 gas = params.TxGasContractCreation 81 } else { 82 gas = params.TxGas 83 } 84 //按事务数据量通气所需的气体 85 if len(data) > 0 { 86 //零字节和非零字节的定价不同 87 var nz uint64 88 for _, byt := range data { 89 if byt != 0 { 90 nz++ 91 } 92 } 93 //确保所有数据组合都不超过uint64 94 if (math.MaxUint64-gas)/params.TxDataNonZeroGas < nz { 95 return 0, vm.ErrOutOfGas 96 } 97 gas += nz * params.TxDataNonZeroGas 98 99 z := uint64(len(data)) - nz 100 if (math.MaxUint64-gas)/params.TxDataZeroGas < z { 101 return 0, vm.ErrOutOfGas 102 } 103 gas += z * params.TxDataZeroGas 104 } 105 return gas, nil 106 } 107 108 //NewStateTransmission初始化并返回新的状态转换对象。 109 func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition { 110 return &StateTransition{ 111 gp: gp, 112 evm: evm, 113 msg: msg, 114 gasPrice: msg.GasPrice(), 115 value: msg.Value(), 116 data: msg.Data(), 117 state: evm.StateDB, 118 } 119 } 120 121 //ApplyMessage通过应用给定消息来计算新状态 122 //反对环境中的旧状态。 123 // 124 //ApplyMessage返回任何EVM执行(如果发生)返回的字节, 125 //使用的气体(包括气体退款)和失败的错误。总是出错 126 //指示一个核心错误,意味着该消息将总是失败。 127 //在一个街区内永远不会被接受。 128 func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) ([]byte, uint64, bool, error) { 129 return NewStateTransition(evm, msg, gp).TransitionDb() 130 } 131 132 //返回邮件的收件人。 133 func (st *StateTransition) to() common.Address { 134 /*st.msg==nil st.msg.to()==nil/*合同创建*/ 135 返回公共地址 136 } 137 返回*st.msg.to()。 138 } 139 140 func (st *StateTransition) useGas(amount uint64) error { 141 如果st.gas<amount 142 返回vm.erroutofgas 143 } 144 ST.气体-=数量 145 146 返回零 147 } 148 149 func(st*statetransition)buygas()错误 150 mgval:=new(big.int).mul(new(big.int).setuint64(st.msg.gas()),st.gasprice) 151 if st.state.getbalance(st.msg.from()).cmp(mgval)<0_ 152 返回不平衡气体 153 } 154 如果错误:=st.gp.subgas(st.msg.gas());错误!= nIL{ 155 返回错误 156 } 157 st.gas+=st.msg.gas()。 158 159 st.initialgas=st.msg.gas()。 160 st.state.subbalance(st.msg.from(),mgval) 161 返回零 162 } 163 164 func(st*statetransition)precheck()错误 165 //确保此事务的nonce是正确的。 166 if st.msg.checknonce() 167 nonce:=st.state.getnonce(st.msg.from()) 168 如果nonce<st.msg.nonce() 169 返回erroncetohohigh 170 else if nonce>st.msg.nonce() 171 返回erroncetoolow 172 } 173 } 174 返回圣布伊加斯(St.Buygas) 175 } 176 177 //transitionDB将通过应用当前消息和 178 //返回包括已用气体在内的结果。如果失败,则返回错误。 179 //错误表示一致性问题。 180 func(st*statetransition)transitiondb()(ret[]byte,usedgas uint64,failed bool,err error) 181 如果err=st.precheck();err!= nIL{ 182 返回 183 } 184 MSG:= ST.MSG 185 发件人:=vm.accountRef(msg.from()) 186 homestead:=st.evm.chainconfig().ishomestead(st.evm.blocknumber) 187 合同创建:=msg.to()==nil 188 189 //支付天然气 190 气体,误差:=内部气体(St.Data,ContractCreation,Homestead) 191 如果犯错!= nIL{ 192 返回nil、0、false、err 193 } 194 如果err=st.usegas(gas);err!= nIL{ 195 返回nil、0、false、err 196 } 197 198 var 199 EVM=ST.EVM 200 //VM错误不影响共识,因此 201 //未分配给err,余额不足除外 202 /错误。 203 VMER误差 204 ) 205 如果合同创建 206 ret,,st.gas,vmerr=evm.create(发送方,st.data,st.gas,st.value) 207 }否则{ 208 //为下一个事务增加nonce 209 st.state.setnonce(msg.from(),st.state.getnonce(sender.address())+1) 210 ret,st.gas,vmerr=evm.call(sender,st.to(),st.data,st.gas,st.value) 211 } 212 如果VMRR!= nIL{ 213 log.debug(“返回的VM有错误”,“err”,vm err) 214 //唯一可能的共识错误是如果没有 215 //有足够的余额进行转移。第一 216 //余额转移永远不会失败。 217 如果vmerr==vm.errUnsuffictBalance 218 返回nil、0、false、vmerr 219 } 220 } 221 S.ReffgdGas() 222 添加平衡(st.evm.coinbase,new(big.int).mul(new(big.int).setuint64(st.gasused()),st.gasprice) 223 224 返回ret,st.gasused(),vmerr!=零 225 } 226 227 func(st*statetransition)refundgas() 228 //申请退款柜台,上限为已用气体的一半。 229 退款:=st.gasused()/2 230 如果退款>st.state.get退款() 231 退款=st.state.get退款() 232 } 233 ST.GAS+=退款 234 235 //剩余气体返回eth,按原汇率交换。 236 剩余:=new(big.int).mul(new(big.int).setuint64(st.gas),st.gasprice) 237 st.state.addbalance(st.msg.from(),剩余) 238 239 //同时将剩余气体返回至区块气计数器,因此 240 //可用于下一个事务。 241 添加气体(ST.GAS) 242 } 243 244 //gas used返回状态转换所消耗的气体量。 245 func(st*statetransition)gasused()uint64_ 246 返回St.InitialGas-St.Gas 247 } 248