mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 23:26:44 +00:00
Move fee burning and tipping out of state transition to reduce read/write dependencies between transactions
This commit is contained in:
parent
bbcc6dd0ad
commit
61accb021a
2 changed files with 127 additions and 47 deletions
|
|
@ -55,16 +55,17 @@ type ExecutionTask struct {
|
|||
msg types.Message
|
||||
config *params.ChainConfig
|
||||
|
||||
gasLimit uint64
|
||||
blockNumber *big.Int
|
||||
blockHash common.Hash
|
||||
blockContext vm.BlockContext
|
||||
tx *types.Transaction
|
||||
index int
|
||||
statedb *state.StateDB // State database that stores the modified values after tx execution.
|
||||
cleanStateDB *state.StateDB // A clean copy of the initial statedb. It should not be modified.
|
||||
evmConfig vm.Config
|
||||
result *ExecutionResult
|
||||
gasLimit uint64
|
||||
blockNumber *big.Int
|
||||
blockHash common.Hash
|
||||
blockContext vm.BlockContext
|
||||
tx *types.Transaction
|
||||
index int
|
||||
statedb *state.StateDB // State database that stores the modified values after tx execution.
|
||||
cleanStateDB *state.StateDB // A clean copy of the initial statedb. It should not be modified.
|
||||
evmConfig vm.Config
|
||||
result *ExecutionResult
|
||||
shouldDelayFeeCal *bool
|
||||
}
|
||||
|
||||
func (task *ExecutionTask) Execute(mvh *blockstm.MVHashMap, incarnation int) (err error) {
|
||||
|
|
@ -91,7 +92,11 @@ func (task *ExecutionTask) Execute(mvh *blockstm.MVHashMap, incarnation int) (er
|
|||
}()
|
||||
|
||||
// Apply the transaction to the current state (included in the env).
|
||||
result, err := ApplyMessage(evm, task.msg, new(GasPool).AddGas(task.gasLimit))
|
||||
if *task.shouldDelayFeeCal {
|
||||
task.result, err = ApplyMessageNoFeeBurnOrTip(evm, task.msg, new(GasPool).AddGas(task.gasLimit))
|
||||
} else {
|
||||
task.result, err = ApplyMessage(evm, task.msg, new(GasPool).AddGas(task.gasLimit))
|
||||
}
|
||||
|
||||
if task.statedb.HadInvalidRead() || err != nil {
|
||||
err = blockstm.ErrExecAbort
|
||||
|
|
@ -100,8 +105,6 @@ func (task *ExecutionTask) Execute(mvh *blockstm.MVHashMap, incarnation int) (er
|
|||
|
||||
task.statedb.Finalise(false)
|
||||
|
||||
task.result = result
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -140,6 +143,8 @@ func (p *ParallelStateProcessor) Process(block *types.Block, statedb *state.Stat
|
|||
|
||||
tasks := make([]blockstm.ExecTask, 0, len(block.Transactions()))
|
||||
|
||||
shouldDelayFeeCal := true
|
||||
|
||||
// Iterate over and process the individual transactions
|
||||
for i, tx := range block.Transactions() {
|
||||
msg, err := tx.AsMessage(types.MakeSigner(p.config, header.Number), header.BaseFee)
|
||||
|
|
@ -148,18 +153,26 @@ func (p *ParallelStateProcessor) Process(block *types.Block, statedb *state.Stat
|
|||
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
|
||||
}
|
||||
|
||||
bc := NewEVMBlockContext(header, p.bc, nil)
|
||||
|
||||
cleansdb := statedb.Copy()
|
||||
|
||||
if msg.From() == bc.Coinbase {
|
||||
shouldDelayFeeCal = false
|
||||
}
|
||||
|
||||
task := &ExecutionTask{
|
||||
msg: msg,
|
||||
config: p.config,
|
||||
gasLimit: block.GasLimit(),
|
||||
blockNumber: blockNumber,
|
||||
blockHash: blockHash,
|
||||
tx: tx,
|
||||
index: i,
|
||||
cleanStateDB: cleansdb,
|
||||
blockContext: NewEVMBlockContext(header, p.bc, nil),
|
||||
msg: msg,
|
||||
config: p.config,
|
||||
gasLimit: block.GasLimit(),
|
||||
blockNumber: blockNumber,
|
||||
blockHash: blockHash,
|
||||
tx: tx,
|
||||
index: i,
|
||||
cleanStateDB: cleansdb,
|
||||
blockContext: bc,
|
||||
evmConfig: cfg,
|
||||
shouldDelayFeeCal: &shouldDelayFeeCal,
|
||||
}
|
||||
|
||||
tasks = append(tasks, task)
|
||||
|
|
@ -172,15 +185,45 @@ func (p *ParallelStateProcessor) Process(block *types.Block, statedb *state.Stat
|
|||
return nil, nil, 0, err
|
||||
}
|
||||
|
||||
london := p.config.IsLondon(blockNumber)
|
||||
|
||||
for _, task := range tasks {
|
||||
task := task.(*ExecutionTask)
|
||||
statedb.Prepare(task.tx.Hash(), task.index)
|
||||
|
||||
coinbaseBalance := statedb.GetBalance(task.blockContext.Coinbase)
|
||||
|
||||
statedb.ApplyMVWriteSet(task.MVWriteList())
|
||||
|
||||
for _, l := range task.statedb.GetLogs(task.tx.Hash(), blockHash) {
|
||||
statedb.AddLog(l)
|
||||
}
|
||||
|
||||
if shouldDelayFeeCal {
|
||||
if london {
|
||||
statedb.AddBalance(task.result.BurntContractAddress, task.result.FeeBurnt)
|
||||
}
|
||||
|
||||
statedb.AddBalance(task.blockContext.Coinbase, task.result.FeeTipped)
|
||||
output1 := new(big.Int).SetBytes(task.result.senderInitBalance.Bytes())
|
||||
output2 := new(big.Int).SetBytes(coinbaseBalance.Bytes())
|
||||
|
||||
// Deprecating transfer log and will be removed in future fork. PLEASE DO NOT USE this transfer log going forward. Parameters won't get updated as expected going forward with EIP1559
|
||||
// add transfer log
|
||||
AddFeeTransferLog(
|
||||
statedb,
|
||||
|
||||
task.msg.From(),
|
||||
task.blockContext.Coinbase,
|
||||
|
||||
task.result.FeeTipped,
|
||||
task.result.senderInitBalance,
|
||||
coinbaseBalance,
|
||||
output1.Sub(output1, task.result.FeeTipped),
|
||||
output2.Add(output2, task.result.FeeTipped),
|
||||
)
|
||||
}
|
||||
|
||||
for k, v := range task.statedb.Preimages() {
|
||||
statedb.AddPreimage(k, v)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,6 +62,11 @@ type StateTransition struct {
|
|||
data []byte
|
||||
state vm.StateDB
|
||||
evm *vm.EVM
|
||||
|
||||
// If true, fee burning and tipping won't happen during transition. Instead, their values will be included in the
|
||||
// ExecutionResult, which caller can use the values to update the balance of burner and coinbase account.
|
||||
// This is useful during parallel state transition, where the common account read/write should be minimized.
|
||||
noFeeBurnAndTip bool
|
||||
}
|
||||
|
||||
// Message represents a message sent to a contract.
|
||||
|
|
@ -84,9 +89,13 @@ type Message interface {
|
|||
// ExecutionResult includes all output after executing given evm
|
||||
// message no matter the execution itself is successful or not.
|
||||
type ExecutionResult struct {
|
||||
UsedGas uint64 // Total used gas but include the refunded gas
|
||||
Err error // Any error encountered during the execution(listed in core/vm/errors.go)
|
||||
ReturnData []byte // Returned data from evm(function result or data supplied with revert opcode)
|
||||
UsedGas uint64 // Total used gas but include the refunded gas
|
||||
Err error // Any error encountered during the execution(listed in core/vm/errors.go)
|
||||
ReturnData []byte // Returned data from evm(function result or data supplied with revert opcode)
|
||||
senderInitBalance *big.Int
|
||||
FeeBurnt *big.Int
|
||||
BurntContractAddress common.Address
|
||||
FeeTipped *big.Int
|
||||
}
|
||||
|
||||
// Unwrap returns the internal evm error which allows us for further
|
||||
|
|
@ -183,6 +192,13 @@ func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) (*ExecutionResult, erro
|
|||
return NewStateTransition(evm, msg, gp).TransitionDb()
|
||||
}
|
||||
|
||||
func ApplyMessageNoFeeBurnOrTip(evm *vm.EVM, msg Message, gp *GasPool) (*ExecutionResult, error) {
|
||||
st := NewStateTransition(evm, msg, gp)
|
||||
st.noFeeBurnAndTip = true
|
||||
|
||||
return st.TransitionDb()
|
||||
}
|
||||
|
||||
// to returns the recipient of the message.
|
||||
func (st *StateTransition) to() common.Address {
|
||||
if st.msg == nil || st.msg.To() == nil /* contract creation */ {
|
||||
|
|
@ -276,7 +292,12 @@ func (st *StateTransition) preCheck() error {
|
|||
// nil evm execution result.
|
||||
func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
||||
input1 := st.state.GetBalance(st.msg.From())
|
||||
input2 := st.state.GetBalance(st.evm.Context.Coinbase)
|
||||
|
||||
var input2 *big.Int
|
||||
|
||||
if !st.noFeeBurnAndTip {
|
||||
input2 = st.state.GetBalance(st.evm.Context.Coinbase)
|
||||
}
|
||||
|
||||
// First check this message satisfies all consensus rules before
|
||||
// applying the message. The rules include these clauses
|
||||
|
|
@ -342,34 +363,50 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
|||
effectiveTip = cmath.BigMin(st.gasTipCap, new(big.Int).Sub(st.gasFeeCap, st.evm.Context.BaseFee))
|
||||
}
|
||||
amount := new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), effectiveTip)
|
||||
|
||||
var burnAmount *big.Int
|
||||
|
||||
var burntContractAddress common.Address
|
||||
|
||||
if london {
|
||||
burntContractAddress := common.HexToAddress(st.evm.ChainConfig().Bor.CalculateBurntContract(st.evm.Context.BlockNumber.Uint64()))
|
||||
burnAmount := new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.evm.Context.BaseFee)
|
||||
st.state.AddBalance(burntContractAddress, burnAmount)
|
||||
burntContractAddress = common.HexToAddress(st.evm.ChainConfig().Bor.CalculateBurntContract(st.evm.Context.BlockNumber.Uint64()))
|
||||
burnAmount = new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.evm.Context.BaseFee)
|
||||
|
||||
if !st.noFeeBurnAndTip {
|
||||
st.state.AddBalance(burntContractAddress, burnAmount)
|
||||
}
|
||||
}
|
||||
st.state.AddBalance(st.evm.Context.Coinbase, amount)
|
||||
output1 := new(big.Int).SetBytes(input1.Bytes())
|
||||
output2 := new(big.Int).SetBytes(input2.Bytes())
|
||||
|
||||
// Deprecating transfer log and will be removed in future fork. PLEASE DO NOT USE this transfer log going forward. Parameters won't get updated as expected going forward with EIP1559
|
||||
// add transfer log
|
||||
AddFeeTransferLog(
|
||||
st.state,
|
||||
if !st.noFeeBurnAndTip {
|
||||
st.state.AddBalance(st.evm.Context.Coinbase, amount)
|
||||
|
||||
msg.From(),
|
||||
st.evm.Context.Coinbase,
|
||||
output1 := new(big.Int).SetBytes(input1.Bytes())
|
||||
output2 := new(big.Int).SetBytes(input2.Bytes())
|
||||
|
||||
amount,
|
||||
input1,
|
||||
input2,
|
||||
output1.Sub(output1, amount),
|
||||
output2.Add(output2, amount),
|
||||
)
|
||||
// Deprecating transfer log and will be removed in future fork. PLEASE DO NOT USE this transfer log going forward. Parameters won't get updated as expected going forward with EIP1559
|
||||
// add transfer log
|
||||
AddFeeTransferLog(
|
||||
st.state,
|
||||
|
||||
msg.From(),
|
||||
st.evm.Context.Coinbase,
|
||||
|
||||
amount,
|
||||
input1,
|
||||
input2,
|
||||
output1.Sub(output1, amount),
|
||||
output2.Add(output2, amount),
|
||||
)
|
||||
}
|
||||
|
||||
return &ExecutionResult{
|
||||
UsedGas: st.gasUsed(),
|
||||
Err: vmerr,
|
||||
ReturnData: ret,
|
||||
UsedGas: st.gasUsed(),
|
||||
Err: vmerr,
|
||||
ReturnData: ret,
|
||||
senderInitBalance: input1,
|
||||
FeeBurnt: burnAmount,
|
||||
BurntContractAddress: burntContractAddress,
|
||||
FeeTipped: amount,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue