mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-11 06:23:47 +00:00
Track burnt and selfdestruct withdraw bal changes
This commit is contained in:
parent
9360cab0df
commit
0967291487
3 changed files with 99 additions and 32 deletions
|
|
@ -33,11 +33,19 @@ const (
|
||||||
BalanceChangeGasRefund = 9
|
BalanceChangeGasRefund = 9
|
||||||
BalanceChangeTouchAccount = 10
|
BalanceChangeTouchAccount = 10
|
||||||
// TODO: rename (debit, credit)
|
// TODO: rename (debit, credit)
|
||||||
BalanceChangeSuicideRefund = 11
|
// BalanceChangeSuicideRefund is added to the recipient as indicated by a selfdestructing account.
|
||||||
|
BalanceChangeSuicideRefund = 11
|
||||||
|
// BalanceChangeSuicideWithdraw is deducted from a contract due to self-destruct.
|
||||||
|
// This can happen either at the point of self-destruction, or at the end of the tx
|
||||||
|
// if ether was sent to contract post-selfdestruct.
|
||||||
BalanceChangeSuicideWithdraw = 12
|
BalanceChangeSuicideWithdraw = 12
|
||||||
// TODO: add method on statedb to track burn without Add/Sub balance
|
// BalanceChangeBurn accounts for:
|
||||||
// Or: Track via OnBurn
|
// - EIP-1559 burnt fees
|
||||||
// 1559 burn, blob burn, withdraw to self via selfdestruct burn, receive ether after selfdestruct (at end of tx)
|
// - ether that is sent to a self-destructed contract within the same tx (captured at end of tx)
|
||||||
BalanceChangeBurn = 13
|
// Note it doesn't account for a self-destruct which appoints same contract as recipient.
|
||||||
BalanceChangeWithdrawal = 14
|
BalanceChangeBurn = 13
|
||||||
|
// BalanceChangeBurnRefund is refunded to an account at the end of transaction based on
|
||||||
|
// gas usage from the estimated burn amount.
|
||||||
|
BalanceChangeBurnRefund = 14
|
||||||
|
BalanceChangeWithdrawal = 15
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -476,13 +476,18 @@ func (s *StateDB) SelfDestruct(addr common.Address) {
|
||||||
if stateObject == nil {
|
if stateObject == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
var (
|
||||||
|
prev = new(big.Int).Set(stateObject.Balance())
|
||||||
|
n = new(big.Int)
|
||||||
|
)
|
||||||
s.journal.append(selfDestructChange{
|
s.journal.append(selfDestructChange{
|
||||||
account: &addr,
|
account: &addr,
|
||||||
prev: stateObject.selfDestructed,
|
prev: stateObject.selfDestructed,
|
||||||
prevbalance: new(big.Int).Set(stateObject.Balance()),
|
prevbalance: prev,
|
||||||
})
|
})
|
||||||
|
s.logger.OnBalanceChange(addr, prev, n, BalanceChangeSuicideWithdraw)
|
||||||
stateObject.markSelfdestructed()
|
stateObject.markSelfdestructed()
|
||||||
stateObject.data.Balance = new(big.Int)
|
stateObject.data.Balance = n
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StateDB) Selfdestruct6780(addr common.Address) {
|
func (s *StateDB) Selfdestruct6780(addr common.Address) {
|
||||||
|
|
@ -870,6 +875,10 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) {
|
||||||
if obj.selfDestructed || (deleteEmptyObjects && obj.empty()) {
|
if obj.selfDestructed || (deleteEmptyObjects && obj.empty()) {
|
||||||
obj.deleted = true
|
obj.deleted = true
|
||||||
|
|
||||||
|
// If ether was sent to account post-selfdestruct it is burnt.
|
||||||
|
if bal := obj.Balance(); bal.Sign() != 0 {
|
||||||
|
s.logger.OnBalanceChange(obj.address, bal, new(big.Int), BalanceChangeBurn)
|
||||||
|
}
|
||||||
// We need to maintain account deletions explicitly (will remain
|
// We need to maintain account deletions explicitly (will remain
|
||||||
// set indefinitely). Note only the first occurred self-destruct
|
// set indefinitely). Note only the first occurred self-destruct
|
||||||
// event is tracked.
|
// event is tracked.
|
||||||
|
|
|
||||||
|
|
@ -233,44 +233,84 @@ func (st *StateTransition) to() common.Address {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *StateTransition) buyGas() error {
|
func (st *StateTransition) buyGas() error {
|
||||||
mgval := new(big.Int).SetUint64(st.msg.GasLimit)
|
|
||||||
mgval = mgval.Mul(mgval, st.msg.GasPrice)
|
|
||||||
balanceCheck := new(big.Int).Set(mgval)
|
|
||||||
if st.msg.GasFeeCap != nil {
|
if st.msg.GasFeeCap != nil {
|
||||||
balanceCheck.SetUint64(st.msg.GasLimit)
|
if err := st.buy1559Gas(); err != nil {
|
||||||
balanceCheck = balanceCheck.Mul(balanceCheck, st.msg.GasFeeCap)
|
return err
|
||||||
balanceCheck.Add(balanceCheck, st.msg.Value)
|
}
|
||||||
}
|
} else {
|
||||||
if st.evm.ChainConfig().IsCancun(st.evm.Context.BlockNumber, st.evm.Context.Time) {
|
if err := st.buyLegacyGas(); err != nil {
|
||||||
if blobGas := st.blobGasUsed(); blobGas > 0 {
|
return err
|
||||||
// Check that the user has enough funds to cover blobGasUsed * tx.BlobGasFeeCap
|
|
||||||
blobBalanceCheck := new(big.Int).SetUint64(blobGas)
|
|
||||||
blobBalanceCheck.Mul(blobBalanceCheck, st.msg.BlobGasFeeCap)
|
|
||||||
balanceCheck.Add(balanceCheck, blobBalanceCheck)
|
|
||||||
// Pay for blobGasUsed * actual blob fee
|
|
||||||
blobFee := new(big.Int).SetUint64(blobGas)
|
|
||||||
blobFee.Mul(blobFee, st.evm.Context.BlobBaseFee)
|
|
||||||
mgval.Add(mgval, blobFee)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if have, want := st.state.GetBalance(st.msg.From), balanceCheck; have.Cmp(want) < 0 {
|
if st.evm.ChainConfig().IsCancun(st.evm.Context.BlockNumber, st.evm.Context.Time) {
|
||||||
return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From.Hex(), have, want)
|
if err := st.buyBlobGas(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := st.gp.SubGas(st.msg.GasLimit); err != nil {
|
if err := st.gp.SubGas(st.msg.GasLimit); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if st.evm.Config.Tracer != nil {
|
if st.evm.Config.Tracer != nil {
|
||||||
st.evm.Config.Tracer.OnGasChange(0, st.msg.GasLimit, vm.GasChangeTxInitialBalance)
|
st.evm.Config.Tracer.OnGasChange(0, st.msg.GasLimit, vm.GasChangeTxInitialBalance)
|
||||||
}
|
}
|
||||||
|
|
||||||
st.gasRemaining += st.msg.GasLimit
|
st.gasRemaining += st.msg.GasLimit
|
||||||
|
|
||||||
st.initialGas = st.msg.GasLimit
|
st.initialGas = st.msg.GasLimit
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *StateTransition) buyLegacyGas() error {
|
||||||
|
mgval := new(big.Int).SetUint64(st.msg.GasLimit)
|
||||||
|
mgval = mgval.Mul(mgval, st.msg.GasPrice)
|
||||||
|
balanceCheck := new(big.Int).Set(mgval)
|
||||||
|
if have, want := st.state.GetBalance(st.msg.From), balanceCheck; have.Cmp(want) < 0 {
|
||||||
|
return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From.Hex(), have, want)
|
||||||
|
}
|
||||||
st.state.SubBalance(st.msg.From, mgval, state.BalanceChangeGasBuy)
|
st.state.SubBalance(st.msg.From, mgval, state.BalanceChangeGasBuy)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// buy1559Gas purchases gas according to EIP-1559 rules. See:
|
||||||
|
// https://eips.ethereum.org/EIPS/eip-1559
|
||||||
|
func (st *StateTransition) buy1559Gas() error {
|
||||||
|
balanceCheck := new(big.Int).SetUint64(st.msg.GasLimit)
|
||||||
|
balanceCheck = balanceCheck.Mul(balanceCheck, st.msg.GasFeeCap)
|
||||||
|
balanceCheck.Add(balanceCheck, st.msg.Value)
|
||||||
|
if have, want := st.state.GetBalance(st.msg.From), balanceCheck; have.Cmp(want) < 0 {
|
||||||
|
return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From.Hex(), have, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
burnt := new(big.Int).SetUint64(st.msg.GasLimit)
|
||||||
|
burnt = burnt.Mul(burnt, st.evm.Context.BaseFee)
|
||||||
|
st.state.SubBalance(st.msg.From, burnt, state.BalanceChangeBurn)
|
||||||
|
|
||||||
|
effectiveTip := cmath.BigMin(st.msg.GasTipCap, new(big.Int).Sub(st.msg.GasFeeCap, st.evm.Context.BaseFee))
|
||||||
|
tipVal := new(big.Int).SetUint64(st.msg.GasLimit)
|
||||||
|
tipVal = tipVal.Mul(tipVal, effectiveTip)
|
||||||
|
st.state.SubBalance(st.msg.From, tipVal, state.BalanceChangeGasBuy)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// buyBlobGas purchases blob gas as per:
|
||||||
|
// https://eips.ethereum.org/EIPS/eip-4844
|
||||||
|
func (st *StateTransition) buyBlobGas() error {
|
||||||
|
if blobGas := st.blobGasUsed(); blobGas > 0 {
|
||||||
|
// Check that the user has enough funds to cover blobGasUsed * tx.BlobGasFeeCap
|
||||||
|
balanceCheck := new(big.Int).SetUint64(blobGas)
|
||||||
|
balanceCheck.Mul(balanceCheck, st.msg.BlobGasFeeCap)
|
||||||
|
if have, want := st.state.GetBalance(st.msg.From), balanceCheck; have.Cmp(want) < 0 {
|
||||||
|
return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From.Hex(), have, want)
|
||||||
|
}
|
||||||
|
// Pay for blobGasUsed * actual blob fee
|
||||||
|
blobFee := new(big.Int).SetUint64(blobGas)
|
||||||
|
blobFee.Mul(blobFee, st.evm.Context.BlobBaseFee)
|
||||||
|
st.state.SubBalance(st.msg.From, blobFee, state.BalanceChangeBurn)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (st *StateTransition) preCheck() error {
|
func (st *StateTransition) preCheck() error {
|
||||||
// Only check transactions that are not fake
|
// Only check transactions that are not fake
|
||||||
msg := st.msg
|
msg := st.msg
|
||||||
|
|
@ -467,8 +507,18 @@ func (st *StateTransition) refundGas(refundQuotient uint64) uint64 {
|
||||||
st.gasRemaining += refund
|
st.gasRemaining += refund
|
||||||
|
|
||||||
// Return ETH for remaining gas, exchanged at the original rate.
|
// Return ETH for remaining gas, exchanged at the original rate.
|
||||||
remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gasRemaining), st.msg.GasPrice)
|
gasRemaining := new(big.Int).SetUint64(st.gasRemaining)
|
||||||
st.state.AddBalance(st.msg.From, remaining, state.BalanceChangeGasRefund)
|
if st.msg.GasFeeCap.Sign() == 0 {
|
||||||
|
remaining := new(big.Int).Mul(gasRemaining, st.msg.GasPrice)
|
||||||
|
st.state.AddBalance(st.msg.From, remaining, state.BalanceChangeGasRefund)
|
||||||
|
} else {
|
||||||
|
// Split into burnt gas and tip gas to refund.
|
||||||
|
burnt := new(big.Int).Mul(gasRemaining, st.evm.Context.BaseFee)
|
||||||
|
st.state.AddBalance(st.msg.From, burnt, state.BalanceChangeBurnRefund)
|
||||||
|
effectiveTip := cmath.BigMin(st.msg.GasTipCap, new(big.Int).Sub(st.msg.GasFeeCap, st.evm.Context.BaseFee))
|
||||||
|
tip := new(big.Int).Mul(gasRemaining, effectiveTip)
|
||||||
|
st.state.AddBalance(st.msg.From, tip, state.BalanceChangeGasRefund)
|
||||||
|
}
|
||||||
|
|
||||||
if st.evm.Config.Tracer != nil && st.gasRemaining > 0 {
|
if st.evm.Config.Tracer != nil && st.gasRemaining > 0 {
|
||||||
st.evm.Config.Tracer.OnGasChange(st.gasRemaining, 0, vm.GasChangeTxLeftOverReturned)
|
st.evm.Config.Tracer.OnGasChange(st.gasRemaining, 0, vm.GasChangeTxLeftOverReturned)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue