区块链教程以太坊源码分析core-state-process源码分析(二)

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

原文地址:http://blog.51cto.com/14035944/2307397

时间: 2024-11-05 20:27:30

区块链教程以太坊源码分析core-state-process源码分析(二)的相关文章

{区块链教程}以太坊源码分析fast sync算法二

{区块链教程}以太坊源码分析fast sync算法二:上面的表格应该这样解释:如果我们每隔K个区块头验证一次区块头,在N个区块头之后,伪造的概率小于***者产生SHA3冲突的概率.这也意味着,如果确实发现了伪造,那么最后的N个头部应该被丢弃,因为不够安全.可以从上表中选择任何{N,K}对,为了选择一个看起来好看点的数字,我们选择N = 2048,K = 100.后续可能会根据网络带宽/延迟影响以及可能在一些CPU性能比较受限的设备上运行的情况来进行调整. Using this caveat ho

区块链教程以太坊源码分析core-state源码分析(二)

## statedb.go stateDB用来存储以太坊中关于merkle trie的所有内容. StateDB负责缓存和存储嵌套状态. 这是检索合约和账户的一般查询界面: 数据结构 type StateDB struct { db Database // 后端的数据库 trie Trie // trie树 main account trie // This map holds 'live' objects, which will get modified while processing a

区块链教程以太坊源码分析core-state-process源码分析

StateTransition 状态转换模型 /* The State Transitioning Model 状态转换模型 A state transition is a change made when a transaction is applied to the current world state 状态转换 是指用当前的world state来执行交易,并改变当前的world state The state transitioning model does all all the n

区块链教程以太源码分析accounts账户管理分析

区块链教程以太源码分析accounts账户管理分析. 数据结构分析 ETH的账户管理定义在accounts/manager.go中,其数据结构为: // Manager is an overarching account manager that can communicate with various // backends for signing transactions. type Manager struct { backends map[reflect.Type][]Backend /

【区块链】以太坊(Ethereum )高级进阶实战视频教程

[区块链]以太坊(Ethereum )高级进阶实战视频教程视频教程地址:http://edu.51cto.com/course/14785.html 课程大纲: 课程概要介绍使用bootnode搭建以太坊私有链web3j介绍及基本使用使用web3j管理账户default block parameter以太坊交易详解ERC20代币介绍使用web3j部署ERC20代币合约账户解锁web3j调用代币合约方法(一)web3j调用代币合约方法(二)web3j调用代币合约方法(三)深入sendTransac

4.区块链平台以太坊从入门到精通之 以太币

1.以太币简介 以太币( ether) 是以太坊中使用的货币的名字.它是用于支付在虚拟机中的运算的费用. 了解就可以 2.获取和发送以太币 有三种方式获取 1.成为一名矿工,通过挖矿来获得以太币的奖励. 2.从交易平台处购买或兑换 3. 图形化界面的以太坊客户端集成了https://shapeshift.io/#/coins 接口. 可以直接在客户端上购买以太币. (需要在主网上才可以) 3.集中的交易兑换市场

区块链教程以太源码分析accounts包简介

accounts包实现了eth客户端的钱包和账户管理.账号的数据结构:typeAccount struct { Address common.Address json:"address" // Ethereum account addressderived from the key URLURL json:"url" // Optional resource locator within a backend }钱包interface,是指包含了一个或多个账户的软件钱

区块链:以太坊基础之安装Geth

1.安装cmake 智能合约需要cmake3.x版本才可以编译 # 下载包 wget https://cmake.org/files/v3.3/cmake-3.3.2.tar.gz # 解压 tar zxvf cmake-3.3.2.tar.gz cd cmake-3.3.2 # 安装 ./configure make make install # 编辑环境变量配置文件 vim /etc/profile # 在末尾加上 export PATH=/usr/cmake/cmake-3.3.2/bin

区块链:以太坊基础之搭建私链

1.新建genesis.json {  "config": {    "chainId": 666,    "homesteadBlock": 0,    "eip150Block": 0,    "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000",    "eip