Skip to content

Commit 28e8789

Browse files
handle data gas / data gas fees appropriately (#26)
1 parent 619c609 commit 28e8789

File tree

11 files changed

+94
-43
lines changed

11 files changed

+94
-43
lines changed

accounts/abi/bind/backends/simulated.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,7 @@ func (m callMsg) To() *common.Address { return m.CallMsg.To }
819819
func (m callMsg) GasPrice() *big.Int { return m.CallMsg.GasPrice }
820820
func (m callMsg) GasFeeCap() *big.Int { return m.CallMsg.GasFeeCap }
821821
func (m callMsg) GasTipCap() *big.Int { return m.CallMsg.GasTipCap }
822+
func (m callMsg) MaxFeePerDataGas() *big.Int { return m.CallMsg.MaxFeePerDataGas }
822823
func (m callMsg) Gas() uint64 { return m.CallMsg.Gas }
823824
func (m callMsg) Value() *big.Int { return m.CallMsg.Value }
824825
func (m callMsg) Data() []byte { return m.CallMsg.Data }

consensus/misc/eip4844.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,8 @@ func VerifyEip4844Header(config *params.ChainConfig, parent, header *types.Heade
7171
}
7272
return nil
7373
}
74+
75+
// GetDataGasPrice implements get_data_gas_price from EIP-4844
76+
func GetDataGasPrice(excessDataGas *big.Int) *big.Int {
77+
return FakeExponential(big.NewInt(params.MinDataGasPrice), excessDataGas, big.NewInt(params.DataGasPriceUpdateFraction))
78+
}

core/blockchain_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3923,6 +3923,8 @@ func TestDataBlobTxs(t *testing.T) {
39233923
msg.Nonce = view.Uint64View(0)
39243924
msg.GasFeeCap.SetFromBig(newGwei(5))
39253925
msg.GasTipCap.SetFromBig(big.NewInt(2))
3926+
msg.MaxFeePerDataGas.SetFromBig(big.NewInt(params.MinDataGasPrice))
3927+
// TODO: Add test case for max data fee too low
39263928
msg.BlobVersionedHashes = []common.Hash{one, two}
39273929
txdata := &types.SignedBlobTx{Message: msg}
39283930

core/error.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ var (
8282
// transaction with a tip higher than the total fee cap.
8383
ErrTipAboveFeeCap = errors.New("max priority fee per gas higher than max fee per gas")
8484

85+
// ErrMaxFeePerDataGas is returned if the transaction specified a
86+
// max_fee_per_data_gas that is below the current data gas price.
87+
ErrMaxFeePerDataGas = errors.New("max data fee per gas too low")
88+
8589
// ErrTipVeryHigh is a sanity error to avoid extremely big numbers specified
8690
// in the tip field.
8791
ErrTipVeryHigh = errors.New("max priority fee per gas higher than 2^256-1")

core/state_transition.go

Lines changed: 52 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import (
2323

2424
"github.com/ethereum/go-ethereum/common"
2525
cmath "github.com/ethereum/go-ethereum/common/math"
26-
// "github.com/ethereum/go-ethereum/consensus/misc"
26+
"github.com/ethereum/go-ethereum/consensus/misc"
2727
"github.com/ethereum/go-ethereum/core/types"
2828
"github.com/ethereum/go-ethereum/core/vm"
2929
"github.com/ethereum/go-ethereum/crypto"
@@ -72,6 +72,7 @@ type Message interface {
7272
GasPrice() *big.Int
7373
GasFeeCap() *big.Int
7474
GasTipCap() *big.Int
75+
MaxFeePerDataGas() *big.Int
7576
Gas() uint64
7677
Value() *big.Int
7778

@@ -162,25 +163,22 @@ func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation b
162163
gas += uint64(len(accessList)) * params.TxAccessListAddressGas
163164
gas += uint64(accessList.StorageKeys()) * params.TxAccessListStorageKeyGas
164165
}
165-
// TODO
166-
//if rules.EIP4844 {
167-
//gas += uint64(blobCount) * getBlobGas(blockExcessBlobs)
168-
//}
169166
return gas, nil
170167
}
171168

172169
// NewStateTransition initialises and returns a new state transition object.
173170
func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition {
174171
return &StateTransition{
175-
gp: gp,
176-
evm: evm,
177-
msg: msg,
178-
gasPrice: msg.GasPrice(),
179-
gasFeeCap: msg.GasFeeCap(),
180-
gasTipCap: msg.GasTipCap(),
181-
value: msg.Value(),
182-
data: msg.Data(),
183-
state: evm.StateDB,
172+
gp: gp,
173+
evm: evm,
174+
msg: msg,
175+
gasPrice: msg.GasPrice(),
176+
gasFeeCap: msg.GasFeeCap(),
177+
gasTipCap: msg.GasTipCap(),
178+
maxFeePerDataGas: msg.MaxFeePerDataGas(),
179+
value: msg.Value(),
180+
data: msg.Data(),
181+
state: evm.StateDB,
184182
}
185183
}
186184

@@ -206,21 +204,35 @@ func (st *StateTransition) to() common.Address {
206204
func (st *StateTransition) buyGas() error {
207205
mgval := new(big.Int).SetUint64(st.msg.Gas())
208206
mgval = mgval.Mul(mgval, st.gasPrice)
209-
balanceCheck := mgval
210-
if st.gasFeeCap != nil {
211-
balanceCheck = new(big.Int).SetUint64(st.msg.Gas())
212-
balanceCheck = balanceCheck.Mul(balanceCheck, st.gasFeeCap)
213-
balanceCheck.Add(balanceCheck, st.value)
207+
208+
dgval := new(big.Int)
209+
if st.evm.ChainConfig().IsSharding(st.evm.Context.BlockNumber) {
210+
// add in fee for eip-4844 data blobs if any
211+
dgval.Mul(misc.GetDataGasPrice(st.evm.Context.ExcessDataGas), st.dataGasUsed())
212+
}
213+
214+
balanceCheck := new(big.Int)
215+
if st.gasFeeCap == nil {
216+
balanceCheck.Set(mgval)
217+
} else {
218+
balanceCheck.Add(st.value, dgval)
219+
// EIP-1559 mandates that the sender has enough balance to cover not just actual fee but
220+
// the max gas fee, so we compute this upper bound rather than use mgval here.
221+
maxGasFee := new(big.Int).SetUint64(st.msg.Gas())
222+
maxGasFee.Mul(maxGasFee, st.gasFeeCap)
223+
balanceCheck.Add(balanceCheck, maxGasFee)
214224
}
225+
215226
if have, want := st.state.GetBalance(st.msg.From()), balanceCheck; have.Cmp(want) < 0 {
216227
return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From().Hex(), have, want)
217228
}
218229
if err := st.gp.SubGas(st.msg.Gas()); err != nil {
219230
return err
220231
}
221232
st.gas += st.msg.Gas()
222-
223233
st.initialGas = st.msg.Gas()
234+
235+
mgval.Add(mgval, dgval) // both regular gas fee and data gas fee need to be deducted
224236
st.state.SubBalance(st.msg.From(), mgval)
225237
return nil
226238
}
@@ -270,6 +282,13 @@ func (st *StateTransition) preCheck() error {
270282
}
271283
}
272284
}
285+
if st.evm.ChainConfig().IsSharding(st.evm.Context.BlockNumber) {
286+
dataGasPrice := misc.GetDataGasPrice(st.evm.Context.ExcessDataGas)
287+
if dataGasPrice.Cmp(st.maxFeePerDataGas) > 0 {
288+
return fmt.Errorf("%w: address %v, maxFeePerDataGas: %v dataGasPrice: %v", ErrMaxFeePerDataGas,
289+
st.msg.From().Hex(), st.maxFeePerDataGas, dataGasPrice)
290+
}
291+
}
273292
return st.buyGas()
274293
}
275294

@@ -291,7 +310,9 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
291310
// applying the message. The rules include these clauses
292311
//
293312
// 1. the nonce of the message caller is correct
294-
// 2. caller has enough balance to cover transaction fee(gaslimit * gasprice)
313+
// 2. caller has enough balance to cover:
314+
// Legacy tx: fee(gaslimit * gasprice)
315+
// EIP-1559 tx: tx.value + max-fee(gaslimit * gascap + datagas * datagasprice)
295316
// 3. the amount of gas required is available in the block
296317
// 4. the purchased gas is enough to cover intrinsic usage
297318
// 5. there is no overflow when calculating intrinsic gas
@@ -402,3 +423,13 @@ func (st *StateTransition) refundGas(refundQuotient uint64) {
402423
func (st *StateTransition) gasUsed() uint64 {
403424
return st.initialGas - st.gas
404425
}
426+
427+
func (st *StateTransition) dataGasUsed() *big.Int {
428+
dataGas := new(big.Int)
429+
l := int64(len(st.msg.DataHashes()))
430+
if l != 0 {
431+
dataGas.SetInt64(l)
432+
dataGas.Mul(dataGas, big.NewInt(params.DataGasPerBlob))
433+
}
434+
return dataGas
435+
}

core/tx_pool.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ const (
5454

5555
// txWrapDataMax is the maximum size for the additional wrapper data,
5656
// enough to encode a blob-transaction wrapper data (48 bytes for commitment, 4 for offset, 48 for a commitment)
57-
txWrapDataMax = 4 + 4 + params.MaxBlobsPerTx*(params.FieldElementsPerBlob*32+48)
57+
txWrapDataMax = 4 + 4 + params.MaxBlobsPerBlock*(params.FieldElementsPerBlob*32+48)
5858
)
5959

6060
var (

core/types/data_blob.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,7 @@ func (b *BlobTxWrapData) verifyVersionedHash(inner TxData) error {
481481
if !ok {
482482
return fmt.Errorf("expected signed blob tx, got %T", inner)
483483
}
484-
if a, b := len(blobTx.Message.BlobVersionedHashes), params.MaxBlobsPerTx; a > b {
484+
if a, b := len(blobTx.Message.BlobVersionedHashes), params.MaxBlobsPerBlock; a > b {
485485
return fmt.Errorf("too many blobs in blob tx, got %d, expected no more than %d", a, b)
486486
}
487487
if a, b := len(b.BlobKzgs), len(b.Blobs); a != b {

core/types/transaction.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"github.com/ethereum/go-ethereum/common"
3131
"github.com/ethereum/go-ethereum/common/math"
3232
"github.com/ethereum/go-ethereum/crypto"
33+
"github.com/ethereum/go-ethereum/params"
3334
"github.com/ethereum/go-ethereum/rlp"
3435
)
3536

@@ -403,13 +404,27 @@ func (tx *Transaction) To() *common.Address {
403404
return copyAddressPtr(tx.inner.to())
404405
}
405406

406-
// Cost returns gas * gasPrice + value.
407+
// Cost returns (gas * gasPrice) + (DataGas() * maxDataFeePerGas) + value.
407408
func (tx *Transaction) Cost() *big.Int {
408409
total := new(big.Int).Mul(tx.GasPrice(), new(big.Int).SetUint64(tx.Gas()))
409410
total.Add(total, tx.Value())
411+
dataGasFee := tx.DataGas()
412+
dataGasFee.Mul(dataGasFee, tx.MaxFeePerDataGas())
413+
total.Add(total, dataGasFee)
410414
return total
411415
}
412416

417+
// DataGas implements get_total_data_gas from EIP-4844
418+
func (tx *Transaction) DataGas() *big.Int {
419+
r := new(big.Int)
420+
l := int64(len(tx.DataHashes()))
421+
if l != 0 {
422+
r.SetInt64(l)
423+
r.Mul(r, big.NewInt(params.DataGasPerBlob))
424+
}
425+
return r
426+
}
427+
413428
// RawSignatureValues returns the V, R, S signature values of the transaction.
414429
// The return values should not be modified by the caller.
415430
func (tx *Transaction) RawSignatureValues() (v, r, s *big.Int) {

light/txpool.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error
378378
}
379379

380380
// Transactor should have enough funds to cover the costs
381-
// cost == V + GP * GL
381+
// cost == V + GP * GL + DGP * DG
382382
if b := currentState.GetBalance(from); b.Cmp(tx.Cost()) < 0 {
383383
return core.ErrInsufficientFunds
384384
}
@@ -389,7 +389,6 @@ func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error
389389
EIP2028: pool.istanbul,
390390
EIP4844: pool.eip4844,
391391
}
392-
// TODO: Check DataGas
393392
gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, rules)
394393
if err != nil {
395394
return err

params/protocol_params.go

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -158,20 +158,14 @@ const (
158158
RefundQuotient uint64 = 2
159159
RefundQuotientEIP3529 uint64 = 5
160160

161-
// Fixed cost for sending a data blob.
162-
BlobGas uint64 = 120000
163-
164-
MaxDataGasPerBlock = 1 << 21
165-
DataGasPerBlob = 1 << 17
166-
MaxDataBlobsPerBlock = MaxDataGasPerBlock / DataGasPerBlob
167-
168-
TargetDataGasPerBlock = 1 << 20
169-
170-
MaxBlobsPerTx = 2
171-
MaxBlobsPerBlock = 16
172-
TargetBlobsPerBlock = 8
173-
FieldElementsPerBlob = 4096 // each field element is 32 bytes
174-
GasPriceUpdateFractionPerBlob = 64
161+
// stuff from EIP-4844
162+
FieldElementsPerBlob = 4096 // each field element is 32 bytes
163+
MaxDataGasPerBlock = 1 << 21
164+
DataGasPerBlob = 1 << 17
165+
TargetDataGasPerBlock = 1 << 20
166+
MinDataGasPrice = 10e8
167+
DataGasPriceUpdateFraction = 8902606
168+
MaxBlobsPerBlock = MaxDataGasPerBlock / DataGasPerBlob
175169

176170
BlobVerificationGas uint64 = 1800000
177171
BlobCommitmentVersionKZG uint8 = 0x01

0 commit comments

Comments
 (0)