简介
分析以太坊代码中交易费的处理逻辑。
- 代码:github.com:ethereum/go-ethereum
- 版本:1.14.6
概述
交易费采用先扣除,再返还剩余gas的方式:
- 交易执行前,先按照gasLimit,扣除用户的最大交易费。
- 交易执行过程中,统计gasRemaing以及gasUsed,此时并不扣除。
- 交易执行过程中,有些指令涉及退费,统计相关的refund,此时并不扣除。
- 交易执行后,返还用户剩余gas(gasRemaining+refund)。
- 支付矿工tip费用。
代码分析
核心逻辑位于交易执行的主流程state_transition.go文件的TransitionDb方法中。
1. 扣除最大gas费(gasLimit)
交易执行前,首先会按照用户的gasLimit,以及真实的gasPrice,扣除用户的最大费用
func (st *StateTransition) buyGas() error {
//按照gasLimit计算最大费用
mgval := new(big.Int).SetUint64(st.msg.GasLimit)
mgval.Mul(mgval, st.msg.GasPrice)
...
st.gasRemaining = st.msg.GasLimit
st.initialGas = st.msg.GasLimit
//从用户账户扣除最大费用
mgvalU256, _ := uint256.FromBig(mgval)
st.state.SubBalance(st.msg.From, mgvalU256, tracing.BalanceDecreaseGasBuy)
return nil
}
调用堆栈为:
func (st *StateTransition) buyGas()//state_transition.go func (st *StateTransition) preCheck()//state_transition.go func (st *StateTransition) TransitionDb()//state_transition.go func ApplyMessage(evm *vm.EVM, msg *Message, gp *GasPool)//state_transition.go func ApplyTransactionWithEVM //state_processor.go func ApplyTransaction //state_processor.go
2. 返回gasRemaining以及Refund
在交易执行完成后,计算剩下的gasRemaining,以及退费refund,返还用户。
其中gasRemaing和refund由具体的opcode决定,会在具体指令执行过程中记录。
func (st *StateTransition) refundGas(refundQuotient uint64) uint64 {
// Apply refund counter, capped to a refund quotient
// 计算退费Refund
refund := st.gasUsed() / refundQuotient
if refund > st.state.GetRefund() {
refund = st.state.GetRefund()
}
...
//把退费加在原本的gas剩余gasRemaining上
st.gasRemaining += refund // Return ETH for remaining gas, exchanged at the original rate. remaining := uint256.NewInt(st.gasRemaining)
remaining.Mul(remaining, uint256.MustFromBig(st.msg.GasPrice))
//返还用户
st.state.AddBalance(st.msg.From, remaining, tracing.BalanceIncreaseGasReturn)
}
调用堆栈为:
func (st *StateTransition) refundGas()//state_transition.go func (st *StateTransition) TransitionDb()//state_transition.go func ApplyMessage(evm *vm.EVM, msg *Message, gp *GasPool)//state_transition.go func ApplyTransactionWithEVM //state_processor.go func ApplyTransaction //state_processor.go
3. 矿工coinbase账户增加交易费
支付矿工tip费用。
func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
...
//统计本笔交易使用的gas, gasUsed
fee := new(uint256.Int).SetUint64(st.gasUsed())
fee.Mul(fee, effectiveTipU256)
//给Coinbase账户增加交易费
st.state.AddBalance(st.evm.Context.Coinbase, fee, tracing.BalanceIncreaseRewardTransactionFee)
}
调用堆栈为:
func (st *StateTransition) refundGas()//state_transition.go func (st *StateTransition) TransitionDb()//state_transition.go func ApplyMessage(evm *vm.EVM, msg *Message, gp *GasPool)//state_transition.go func ApplyTransactionWithEVM //state_processor.go func ApplyTransaction //state_processor.go
回复 slot qris 取消回复