Skip to content

Commit 8288f26

Browse files
authored
Implement calldata cost increase per EIP-7623 (#13080) (#13407)
See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-7623.md Issue board - #12401 Cherry pick #13080
1 parent 24b8e92 commit 8288f26

File tree

7 files changed

+89
-26
lines changed

7 files changed

+89
-26
lines changed

core/state_transition.go

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ type Message interface {
104104

105105
// IntrinsicGas computes the 'intrinsic gas' for a message with the given data.
106106
// TODO: convert the input to a struct
107-
func IntrinsicGas(data []byte, accessList types2.AccessList, isContractCreation bool, isHomestead, isEIP2028, isEIP3860 bool, authorizationsLen uint64) (uint64, error) {
107+
func IntrinsicGas(data []byte, accessList types2.AccessList, isContractCreation bool, isHomestead, isEIP2028, isEIP3860, isPrague bool, authorizationsLen uint64) (uint64, uint64, error) {
108108
// Zero and non-zero bytes are priced differently
109109
dataLen := uint64(len(data))
110110
dataNonZeroLen := uint64(0)
@@ -114,11 +114,11 @@ func IntrinsicGas(data []byte, accessList types2.AccessList, isContractCreation
114114
}
115115
}
116116

117-
gas, status := txpoolcfg.CalcIntrinsicGas(dataLen, dataNonZeroLen, authorizationsLen, accessList, isContractCreation, isHomestead, isEIP2028, isEIP3860)
117+
gas, floorGas7623, status := txpoolcfg.CalcIntrinsicGas(dataLen, dataNonZeroLen, authorizationsLen, accessList, isContractCreation, isHomestead, isEIP2028, isEIP3860, isPrague)
118118
if status != txpoolcfg.Success {
119-
return 0, ErrGasUintOverflow
119+
return 0, 0, ErrGasUintOverflow
120120
}
121-
return gas, nil
121+
return gas, floorGas7623, nil
122122
}
123123

124124
// NewStateTransition initialises and returns a new state transition object.
@@ -417,12 +417,12 @@ func (st *StateTransition) TransitionDb(refunds bool, gasBailout bool) (*evmtype
417417
}
418418

419419
// Check clauses 4-5, subtract intrinsic gas if everything is correct
420-
gas, err := IntrinsicGas(st.data, accessTuples, contractCreation, rules.IsHomestead, rules.IsIstanbul, isEIP3860, uint64(len(auths)))
420+
gas, floorGas7623, err := IntrinsicGas(st.data, accessTuples, contractCreation, rules.IsHomestead, rules.IsIstanbul, isEIP3860, rules.IsPrague, uint64(len(auths)))
421421
if err != nil {
422422
return nil, err
423423
}
424-
if st.gasRemaining < gas {
425-
return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gasRemaining, gas)
424+
if st.gasRemaining < gas || st.gasRemaining < floorGas7623 {
425+
return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gasRemaining, max(gas, floorGas7623))
426426
}
427427
st.gasRemaining -= gas
428428

@@ -457,6 +457,11 @@ func (st *StateTransition) TransitionDb(refunds bool, gasBailout bool) (*evmtype
457457
} else {
458458
ret, st.gasRemaining, vmerr = st.evm.Call(sender, st.to(), st.data, st.gasRemaining, st.value, bailout)
459459
}
460+
gasUsed := st.gasUsed()
461+
if gasUsed < floorGas7623 && rules.IsPrague {
462+
gasUsed = floorGas7623
463+
st.gasRemaining = st.initialGas - gasUsed
464+
}
460465
if refunds && !gasBailout {
461466
if rules.IsLondon {
462467
// After EIP-3529: refunds are capped to gasUsed / 5

erigon-lib/common/fixedgas/protocol.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const (
2424
TxDataNonZeroGasEIP2028 uint64 = 16 // Per byte of non zero data attached to a transaction after EIP 2028 (part in Istanbul)
2525
TxAccessListAddressGas uint64 = 2400 // Per address specified in EIP 2930 access list
2626
TxAccessListStorageKeyGas uint64 = 1900 // Per storage key specified in EIP 2930 access list
27+
TxTotalCostFloorPerToken uint64 = 10 // Per token of calldata in a transaction, as a minimum the txn must pay (EIP-7623)
2728

2829
MaxCodeSize = 24576 // Maximum bytecode to permit for a contract
2930

erigon-lib/txpool/pool.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,7 @@ func (p *TxPool) best(n uint16, txs *types.TxsRlp, tx kv.Tx, onTopOf, availableG
727727
best := p.pending.best
728728

729729
isShanghai := p.isShanghai() || p.isAgra()
730+
isPrague := p.isPrague()
730731

731732
txs.Resize(uint(cmp.Min(int(n), len(best.ms))))
732733
var toRemove []*metaTx
@@ -774,7 +775,10 @@ func (p *TxPool) best(n uint16, txs *types.TxsRlp, tx kv.Tx, onTopOf, availableG
774775
// not an exact science using intrinsic gas but as close as we could hope for at
775776
// this stage
776777
authorizationLen := uint64(len(mt.Tx.Authorizations))
777-
intrinsicGas, _ := txpoolcfg.CalcIntrinsicGas(uint64(mt.Tx.DataLen), uint64(mt.Tx.DataNonZeroLen), authorizationLen, nil, mt.Tx.Creation, true, true, isShanghai)
778+
intrinsicGas, floorGas, _ := txpoolcfg.CalcIntrinsicGas(uint64(mt.Tx.DataLen), uint64(mt.Tx.DataNonZeroLen), authorizationLen, nil, mt.Tx.Creation, true, true, isShanghai, isPrague)
779+
if isPrague && floorGas > intrinsicGas {
780+
intrinsicGas = floorGas
781+
}
778782
if intrinsicGas > availableGas {
779783
// we might find another TX with a low enough intrinsic gas to include so carry on
780784
continue
@@ -918,7 +922,11 @@ func (p *TxPool) validateTx(txn *types.TxSlot, isLocal bool, stateCache kvcache.
918922
}
919923
return txpoolcfg.UnderPriced
920924
}
921-
gas, reason := txpoolcfg.CalcIntrinsicGas(uint64(txn.DataLen), uint64(txn.DataNonZeroLen), uint64(authorizationLen), nil, txn.Creation, true, true, isShanghai)
925+
gas, floorGas, reason := txpoolcfg.CalcIntrinsicGas(uint64(txn.DataLen), uint64(txn.DataNonZeroLen), uint64(authorizationLen), nil, txn.Creation, true, true, isShanghai, p.isPrague())
926+
if p.isPrague() && floorGas > gas {
927+
gas = floorGas
928+
}
929+
922930
if txn.Traced {
923931
p.logger.Info(fmt.Sprintf("TX TRACING: validateTx intrinsic gas idHash=%x gas=%d", txn.IDHash, gas))
924932
}

erigon-lib/txpool/pool_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,8 @@ func TestShanghaiIntrinsicGas(t *testing.T) {
634634

635635
for name, c := range cases {
636636
t.Run(name, func(t *testing.T) {
637-
gas, reason := txpoolcfg.CalcIntrinsicGas(c.dataLen, c.dataNonZeroLen, c.authorizationsLen, nil, c.creation, true, true, c.isShanghai)
637+
// Todo (@somnathb1) - Factor in EIP-7623
638+
gas, _, reason := txpoolcfg.CalcIntrinsicGas(c.dataLen, c.dataNonZeroLen, c.authorizationsLen, nil, c.creation, true, true, c.isShanghai, false)
638639
if reason != txpoolcfg.Success {
639640
t.Errorf("expected success but got reason %v", reason)
640641
}

erigon-lib/txpool/txpoolcfg/txpoolcfg.go

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -188,13 +188,13 @@ func (r DiscardReason) String() string {
188188

189189
// CalcIntrinsicGas computes the 'intrinsic gas' for a message with the given data.
190190
// TODO: move input data to a struct
191-
func CalcIntrinsicGas(dataLen, dataNonZeroLen, authorizationsLen uint64, accessList types.AccessList, isContractCreation, isHomestead, isEIP2028, isShanghai bool) (uint64, DiscardReason) {
191+
func CalcIntrinsicGas(dataLen, dataNonZeroLen, authorizationsLen uint64, accessList types.AccessList, isContractCreation, isHomestead, isEIP2028, isShanghai, isPrague bool) (gas uint64, floorGas7623 uint64, d DiscardReason) {
192192
// Set the starting gas for the raw transaction
193-
var gas uint64
194193
if isContractCreation && isHomestead {
195194
gas = fixedgas.TxGasContractCreation
196195
} else {
197196
gas = fixedgas.TxGas
197+
floorGas7623 = fixedgas.TxGas
198198
}
199199
// Bump the required gas by the amount of transactional data
200200
if dataLen > 0 {
@@ -208,68 +208,81 @@ func CalcIntrinsicGas(dataLen, dataNonZeroLen, authorizationsLen uint64, accessL
208208

209209
product, overflow := emath.SafeMul(nz, nonZeroGas)
210210
if overflow {
211-
return 0, GasUintOverflow
211+
return 0, 0, GasUintOverflow
212212
}
213213
gas, overflow = emath.SafeAdd(gas, product)
214214
if overflow {
215-
return 0, GasUintOverflow
215+
return 0, 0, GasUintOverflow
216216
}
217217

218218
z := dataLen - nz
219219

220220
product, overflow = emath.SafeMul(z, fixedgas.TxDataZeroGas)
221221
if overflow {
222-
return 0, GasUintOverflow
222+
return 0, 0, GasUintOverflow
223223
}
224224
gas, overflow = emath.SafeAdd(gas, product)
225225
if overflow {
226-
return 0, GasUintOverflow
226+
return 0, 0, GasUintOverflow
227227
}
228228

229229
if isContractCreation && isShanghai {
230230
numWords := toWordSize(dataLen)
231231
product, overflow = emath.SafeMul(numWords, fixedgas.InitCodeWordGas)
232232
if overflow {
233-
return 0, GasUintOverflow
233+
return 0, 0, GasUintOverflow
234234
}
235235
gas, overflow = emath.SafeAdd(gas, product)
236236
if overflow {
237-
return 0, GasUintOverflow
237+
return 0, 0, GasUintOverflow
238+
}
239+
}
240+
241+
// EIP-7623
242+
if isPrague {
243+
tokenLen := dataLen + 3*nz
244+
dataGas, overflow := emath.SafeMul(tokenLen, fixedgas.TxTotalCostFloorPerToken)
245+
if overflow {
246+
return 0, 0, GasUintOverflow
247+
}
248+
floorGas7623, overflow = emath.SafeAdd(floorGas7623, dataGas)
249+
if overflow {
250+
return 0, 0, GasUintOverflow
238251
}
239252
}
240253
}
241254
if accessList != nil {
242255
product, overflow := emath.SafeMul(uint64(len(accessList)), fixedgas.TxAccessListAddressGas)
243256
if overflow {
244-
return 0, GasUintOverflow
257+
return 0, 0, GasUintOverflow
245258
}
246259
gas, overflow = emath.SafeAdd(gas, product)
247260
if overflow {
248-
return 0, GasUintOverflow
261+
return 0, 0, GasUintOverflow
249262
}
250263

251264
product, overflow = emath.SafeMul(uint64(accessList.StorageKeys()), fixedgas.TxAccessListStorageKeyGas)
252265
if overflow {
253-
return 0, GasUintOverflow
266+
return 0, 0, GasUintOverflow
254267
}
255268
gas, overflow = emath.SafeAdd(gas, product)
256269
if overflow {
257-
return 0, GasUintOverflow
270+
return 0, 0, GasUintOverflow
258271
}
259272
}
260273

261274
// Add the cost of authorizations
262275
product, overflow := emath.SafeMul(authorizationsLen, fixedgas.PerEmptyAccountCost)
263276
if overflow {
264-
return 0, GasUintOverflow
277+
return 0, 0, GasUintOverflow
265278
}
266279

267280
gas, overflow = emath.SafeAdd(gas, product)
268281
if overflow {
269-
return 0, GasUintOverflow
282+
return 0, 0, GasUintOverflow
270283
}
271284

272-
return gas, Success
285+
return gas, floorGas7623, Success
273286
}
274287

275288
// toWordSize returns the ceiled word size required for memory expansion.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2025 The Erigon Authors
2+
// This file is part of Erigon.
3+
//
4+
// Erigon is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Lesser General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// Erigon is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Lesser General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Lesser General Public License
15+
// along with Erigon. If not, see <http://www.gnu.org/licenses/>.
16+
17+
package txpoolcfg
18+
19+
import (
20+
"testing"
21+
22+
"github.com/erigontech/erigon-lib/common/fixedgas"
23+
"github.com/stretchr/testify/assert"
24+
)
25+
26+
func TestZeroDataIntrinsicGas(t *testing.T) {
27+
assert := assert.New(t)
28+
gas, floorGas7623, discardReason := CalcIntrinsicGas(0, 0, 0, nil, false, true, true, true, true)
29+
assert.Equal(discardReason, Success)
30+
assert.Equal(gas, fixedgas.TxGas)
31+
assert.Equal(floorGas7623, fixedgas.TxGas)
32+
}

tests/transaction_test_util.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,10 @@ func (tt *TransactionTest) Run(chainID *big.Int) error {
7575
if stx, ok := tx.(*types.SetCodeTransaction); ok {
7676
authorizationsLen = uint64(len(stx.GetAuthorizations()))
7777
}
78-
requiredGas, err := core.IntrinsicGas(msg.Data(), msg.AccessList(), msg.To() == nil, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai, authorizationsLen)
78+
requiredGas, floorGas, err := core.IntrinsicGas(msg.Data(), msg.AccessList(), msg.To() == nil, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai, rules.IsPrague, authorizationsLen)
79+
if rules.IsPrague && floorGas > requiredGas {
80+
requiredGas = floorGas
81+
}
7982
if err != nil {
8083
return nil, nil, 0, err
8184
}

0 commit comments

Comments
 (0)