学习
实践
活动
专区
工具
TVP
写文章

兄弟连区块链教程core-state-process源码分析

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

关于g0的计算,在黄皮书上由详细的介绍

和黄皮书有一定出入的部分在于if contractCreation && homestead 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

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)

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)

// 拿到所有的日志并创建日志的布隆过滤器.

return receipt, gas, err

}

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181022A121E200?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

关注

腾讯云开发者公众号
10元无门槛代金券
洞察腾讯核心技术
剖析业界实践案例
腾讯云开发者公众号二维码

扫码关注腾讯云开发者

领取腾讯云代金券