美文网首页区块链教程
兄弟连区块链教程以太坊源码分析core-state-proces

兄弟连区块链教程以太坊源码分析core-state-proces

作者: ab6973df9221 | 来源:发表于2018-10-22 17:05 被阅读3次

兄弟连区块链教程以太坊源码分析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

    }

相关文章

网友评论

    本文标题:兄弟连区块链教程以太坊源码分析core-state-proces

    本文链接:https://www.haomeiwen.com/subject/vuigzftx.html