兄弟连区块链教程以太坊源码分析core-state-process源码分析(二): 关于g0的计算,在黄皮书上由详细的介绍 和黄皮书有一定出入的部分在于if contractCreation && homestead {igas.SetUint64(params.TxGasContractCreation) 这是因为 Gtxcreate+Gtransaction = TxGasContractCreation func IntrinsicGas(data []byte, contractCreation, homestead bool) *big.Int { igas := new(big.Int) if contractCreation && homestead { igas.SetUint64(params.TxGasContractCreation) } else { igas.SetUint64(params.TxGas) } if len(data) > 0 { var nz int64 for _, byt := range data { if byt != 0 { nz++ } } m := big.NewInt(nz) m.Mul(m, new(big.Int).SetUint64(params.TxDataNonZeroGas)) igas.Add(igas, m) m.SetInt64(int64(len(data)) - nz) m.Mul(m, new(big.Int).SetUint64(params.TxDataZeroGas)) igas.Add(igas, m) } return igas }
执行前的检查
func (st *StateTransition) preCheck() error { msg := st.msg sender := st.from() // Make sure this transaction's nonce is correct if msg.CheckNonce() { nonce := st.state.GetNonce(sender.Address()) // 当前本地的nonce 需要和 msg的Nonce一样 不然就是状态不同步了。 if nonce < msg.Nonce() { return ErrNonceTooHigh } else if nonce > msg.Nonce() { return ErrNonceTooLow } } return st.buyGas() }
buyGas, 实现Gas的预扣费, 首先就扣除你的GasLimit * GasPrice的钱。 然后根据计算完的状态在退还一部分。
func (st *StateTransition) buyGas() error { mgas := st.msg.Gas() if mgas.BitLen() > 64 { return vm.ErrOutOfGas } mgval := new(big.Int).Mul(mgas, st.gasPrice) var ( state = st.state sender = st.from() ) if state.GetBalance(sender.Address()).Cmp(mgval) < 0 { return errInsufficientBalanceForGas } if err := st.gp.SubGas(mgas); err != nil { // 从区块的gaspool里面减去, 因为区块是由GasLimit限制整个区块的Gas使用的。 return err } st.gas += mgas.Uint64() st.initialGas.Set(mgas) state.SubBalance(sender.Address(), mgval) // 从账号里面减去 GasLimit * GasPrice return nil }
退税,退税是为了奖励大家运行一些能够减轻区块链负担的指令, 比如清空账户的storage. 或者是运行suicide命令来清空账号。
func (st *StateTransition) refundGas() { // Return eth for remaining gas to the sender account, // exchanged at the original rate. sender := st.from() // err already checked remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), st.gasPrice) // 首先把用户还剩下的Gas还回去。 st.state.AddBalance(sender.Address(), remaining) // Apply refund counter, capped to half of the used gas. // 然后退税的总金额不会超过用户Gas总使用的1/2。 uhalf := remaining.Div(st.gasUsed(), common.Big2) refund := math.BigMin(uhalf, st.state.GetRefund()) st.gas += refund.Uint64() // 把退税的金额加到用户账户上。 st.state.AddBalance(sender.Address(), refund.Mul(refund, st.gasPrice)) // Also return remaining gas to the block gas counter so it is // available for the next transaction. // 同时也把退税的钱还给gaspool给下个交易腾点Gas空间。 st.gp.AddGas(new(big.Int).SetUint64(st.gas)) }
## StateProcessor StateTransition是用来处理一个一个的交易的。那么StateProcessor就是用来处理区块级别的交易的。 结构和构造
// StateProcessor is a basic Processor, which takes care of transitioning // state from one point to another. // // StateProcessor implements Processor. type StateProcessor struct { config *params.ChainConfig // Chain configuration options bc *BlockChain // Canonical block chain engine consensus.Engine // Consensus engine used for block rewards } // NewStateProcessor initialises a new StateProcessor. func NewStateProcessor(config *params.ChainConfig, bc *BlockChain, engine consensus.Engine) *StateProcessor { return &StateProcessor{ config: config, bc: bc, engine: engine, } }
Process,这个方法会被blockchain调用。 // Process processes the state changes according to the Ethereum rules by running // the transaction messages using the statedb and applying any rewards to both // the processor (coinbase) and any included uncles. // Process 根据以太坊规则运行交易信息来对statedb进行状态改变,以及奖励挖矿者或者是其他的叔父节点。 // Process returns the receipts and logs accumulated during the process and // returns the amount of gas that was used in the process. If any of the // transactions failed to execute due to insufficient gas it will return an error. // Process返回执行过程中累计的收据和日志,并返回过程中使用的Gas。 如果由于Gas不足而导致任何交易执行失败,将返回错误。 func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, *big.Int, error) { var ( receipts types.Receipts totalUsedGas = big.NewInt(0) header = block.Header() allLogs []*types.Log gp = new(GasPool).AddGas(block.GasLimit()) ) // Mutate the the block and state according to any hard-fork specs // DAO 事件的硬分叉处理 if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { misc.ApplyDAOHardFork(statedb) } // Iterate over and process the individual transactions for i, tx := range block.Transactions() { statedb.Prepare(tx.Hash(), block.Hash(), i) receipt, _, err := ApplyTransaction(p.config, p.bc, nil, gp, statedb, header, tx, totalUsedGas, cfg) if err != nil { return nil, nil, nil, err } receipts = append(receipts, receipt) allLogs = append(allLogs, receipt.Logs...) } // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles(), receipts) // 返回收据 日志 总的Gas使用量和nil return receipts, allLogs, totalUsedGas, nil } ApplyTransaction // ApplyTransaction attempts to apply a transaction to the given state database // and uses the input parameters for its environment. It returns the receipt // for the transaction, gas used and an error if the transaction failed, // indicating the block was invalid. ApplyTransaction尝试将事务应用于给定的状态数据库,并使用其环境的输入参数。 //它返回事务的收据,使用的Gas和错误,如果交易失败,表明块是无效的。 func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, cfg vm.Config) (*types.Receipt, *big.Int, error) { // 把交易转换成Message // 这里如何验证消息确实是Sender发送的。 TODO msg, err := tx.AsMessage(types.MakeSigner(config, header.Number)) if err != nil { return nil, nil, err } // Create a new context to be used in the EVM environment // 每一个交易都创建了新的虚拟机环境。 context := NewEVMContext(msg, header, bc, author) // Create a new environment which holds all relevant information // about the transaction and calling mechanisms. vmenv := vm.NewEVM(context, statedb, config, cfg) // Apply the transaction to the current state (included in the env) _, gas, failed, err := ApplyMessage(vmenv, msg, gp) if err != nil { return nil, nil, err } // Update the state with pending changes // 求得中间状态 var root []byte if config.IsByzantium(header.Number) { statedb.Finalise(true) } else { root = statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes() } usedGas.Add(usedGas, gas) // Create a new receipt for the transaction, storing the intermediate root and gas used by the tx // based on the eip phase, we're passing wether the root touch-delete accounts. // 创建一个收据, 用来存储中间状态的root, 以及交易使用的gas receipt := types.NewReceipt(root, failed, usedGas) receipt.TxHash = tx.Hash() receipt.GasUsed = new(big.Int).Set(gas) // if the transaction created a contract, store the creation address in the receipt. // 如果是创建合约的交易.那么我们把创建地址存储到收据里面. if msg.To() == nil { receipt.ContractAddress = crypto.CreateAddress(vmenv.Context.Origin, tx.Nonce()) } // Set the receipt logs and create a bloom for filtering receipt.Logs = statedb.GetLogs(tx.Hash()) receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) // 拿到所有的日志并创建日志的布隆过滤器. return receipt, gas, err }
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/31557831/viewspace-2217086/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/31557831/viewspace-2217086/