From dde8198639d67450cf737ccca0cf34dcf144a9ba Mon Sep 17 00:00:00 2001 From: Somnath Banerjee Date: Wed, 11 Dec 2024 17:35:04 +0400 Subject: [PATCH 1/2] Implement calldata cost increase per EIP-7623 --- core/state_transition.go | 6 +++--- erigon-lib/common/fixedgas/protocol.go | 1 + txnprovider/txpool/pool.go | 5 +++-- txnprovider/txpool/pool_test.go | 2 +- txnprovider/txpool/txpoolcfg/txpoolcfg.go | 18 +++++++++++++++++- 5 files changed, 25 insertions(+), 7 deletions(-) diff --git a/core/state_transition.go b/core/state_transition.go index 52141f37dbe..b9254a84ddf 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -108,7 +108,7 @@ type Message interface { // IntrinsicGas computes the 'intrinsic gas' for a message with the given data. // TODO: convert the input to a struct -func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation bool, isHomestead, isEIP2028, isEIP3860 bool, authorizationsLen uint64) (uint64, error) { +func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation bool, isHomestead, isEIP2028, isEIP3860, isPrague bool, authorizationsLen uint64) (uint64, error) { // Zero and non-zero bytes are priced differently dataLen := uint64(len(data)) dataNonZeroLen := uint64(0) @@ -118,7 +118,7 @@ func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation b } } - gas, status := txpoolcfg.CalcIntrinsicGas(dataLen, dataNonZeroLen, authorizationsLen, accessList, isContractCreation, isHomestead, isEIP2028, isEIP3860) + gas, status := txpoolcfg.CalcIntrinsicGas(dataLen, dataNonZeroLen, authorizationsLen, accessList, isContractCreation, isHomestead, isEIP2028, isEIP3860, isPrague) if status != txpoolcfg.Success { return 0, ErrGasUintOverflow } @@ -460,7 +460,7 @@ func (st *StateTransition) TransitionDb(refunds bool, gasBailout bool) (*evmtype } // Check clauses 4-5, subtract intrinsic gas if everything is correct - gas, err := IntrinsicGas(st.data, accessTuples, contractCreation, rules.IsHomestead, rules.IsIstanbul, isEIP3860, uint64(len(auths))) + gas, err := IntrinsicGas(st.data, accessTuples, contractCreation, rules.IsHomestead, rules.IsIstanbul, isEIP3860, rules.IsPrague, uint64(len(auths))) if err != nil { return nil, err } diff --git a/erigon-lib/common/fixedgas/protocol.go b/erigon-lib/common/fixedgas/protocol.go index cc73737a733..c002d070cf3 100644 --- a/erigon-lib/common/fixedgas/protocol.go +++ b/erigon-lib/common/fixedgas/protocol.go @@ -24,6 +24,7 @@ const ( TxDataNonZeroGasEIP2028 uint64 = 16 // Per byte of non zero data attached to a transaction after EIP 2028 (part in Istanbul) TxAccessListAddressGas uint64 = 2400 // Per address specified in EIP 2930 access list TxAccessListStorageKeyGas uint64 = 1900 // Per storage key specified in EIP 2930 access list + TxTotalCostFloorPerToken uint64 = 10 // Per token of calldata in a transaction, as a minimum the txn must pay (EIP-7623) MaxCodeSize = 24576 // Maximum bytecode to permit for a contract diff --git a/txnprovider/txpool/pool.go b/txnprovider/txpool/pool.go index d0600b3476a..9c1b22ce675 100644 --- a/txnprovider/txpool/pool.go +++ b/txnprovider/txpool/pool.go @@ -654,6 +654,7 @@ func (p *TxPool) best(ctx context.Context, n int, txns *TxnsRlp, onTopOf, availa best := p.pending.best isShanghai := p.isShanghai() || p.isAgra() + isPrague := p.isCancun() txns.Resize(uint(min(n, len(best.ms)))) var toRemove []*metaTxn @@ -707,7 +708,7 @@ func (p *TxPool) best(ctx context.Context, n int, txns *TxnsRlp, onTopOf, availa // not an exact science using intrinsic gas but as close as we could hope for at // this stage authorizationLen := uint64(len(mt.TxnSlot.Authorizations)) - intrinsicGas, _ := txpoolcfg.CalcIntrinsicGas(uint64(mt.TxnSlot.DataLen), uint64(mt.TxnSlot.DataNonZeroLen), authorizationLen, nil, mt.TxnSlot.Creation, true, true, isShanghai) + intrinsicGas, _ := txpoolcfg.CalcIntrinsicGas(uint64(mt.TxnSlot.DataLen), uint64(mt.TxnSlot.DataNonZeroLen), authorizationLen, nil, mt.TxnSlot.Creation, true, true, isShanghai, isPrague) if intrinsicGas > availableGas { // we might find another txn with a low enough intrinsic gas to include so carry on continue @@ -882,7 +883,7 @@ func (p *TxPool) validateTx(txn *TxnSlot, isLocal bool, stateCache kvcache.Cache } return txpoolcfg.UnderPriced } - gas, reason := txpoolcfg.CalcIntrinsicGas(uint64(txn.DataLen), uint64(txn.DataNonZeroLen), uint64(authorizationLen), nil, txn.Creation, true, true, isShanghai) + gas, reason := txpoolcfg.CalcIntrinsicGas(uint64(txn.DataLen), uint64(txn.DataNonZeroLen), uint64(authorizationLen), nil, txn.Creation, true, true, isShanghai, p.isPrague()) if txn.Traced { p.logger.Info(fmt.Sprintf("TX TRACING: validateTx intrinsic gas idHash=%x gas=%d", txn.IDHash, gas)) } diff --git a/txnprovider/txpool/pool_test.go b/txnprovider/txpool/pool_test.go index 3d2f15b8db6..89d55cd3fd5 100644 --- a/txnprovider/txpool/pool_test.go +++ b/txnprovider/txpool/pool_test.go @@ -632,7 +632,7 @@ func TestShanghaiIntrinsicGas(t *testing.T) { for name, c := range cases { t.Run(name, func(t *testing.T) { - gas, reason := txpoolcfg.CalcIntrinsicGas(c.dataLen, c.dataNonZeroLen, c.authorizationsLen, nil, c.creation, true, true, c.isShanghai) + gas, reason := txpoolcfg.CalcIntrinsicGas(c.dataLen, c.dataNonZeroLen, c.authorizationsLen, nil, c.creation, true, true, c.isShanghai, false) if reason != txpoolcfg.Success { t.Errorf("expected success but got reason %v", reason) } diff --git a/txnprovider/txpool/txpoolcfg/txpoolcfg.go b/txnprovider/txpool/txpoolcfg/txpoolcfg.go index 27ef3a979b0..18543d105e7 100644 --- a/txnprovider/txpool/txpoolcfg/txpoolcfg.go +++ b/txnprovider/txpool/txpoolcfg/txpoolcfg.go @@ -190,7 +190,7 @@ func (r DiscardReason) String() string { // CalcIntrinsicGas computes the 'intrinsic gas' for a message with the given data. // TODO: move input data to a struct -func CalcIntrinsicGas(dataLen, dataNonZeroLen, authorizationsLen uint64, accessList types.AccessList, isContractCreation, isHomestead, isEIP2028, isShanghai bool) (uint64, DiscardReason) { +func CalcIntrinsicGas(dataLen, dataNonZeroLen, authorizationsLen uint64, accessList types.AccessList, isContractCreation, isHomestead, isEIP2028, isShanghai, isPrague bool) (uint64, DiscardReason) { // Set the starting gas for the raw transaction var gas uint64 if isContractCreation && isHomestead { @@ -239,6 +239,22 @@ func CalcIntrinsicGas(dataLen, dataNonZeroLen, authorizationsLen uint64, accessL return 0, GasUintOverflow } } + + // EIP-7623 + if isPrague { + tokenLen := dataLen + 3*nz + floorCost, overflow := emath.SafeMul(tokenLen, fixedgas.TxTotalCostFloorPerToken) + if overflow { + return 0, GasUintOverflow + } + floorCost, overflow = emath.SafeAdd(floorCost, fixedgas.TxGas) + if overflow { + return 0, GasUintOverflow + } + if floorCost > gas { + gas = floorCost + } + } } if accessList != nil { product, overflow := emath.SafeMul(uint64(len(accessList)), fixedgas.TxAccessListAddressGas) From 7e22f1e6b5026ba2a860cd88979682e0048a17e2 Mon Sep 17 00:00:00 2001 From: Somnath Banerjee Date: Thu, 12 Dec 2024 14:45:17 +0400 Subject: [PATCH 2/2] Fix --- tests/transaction_test_util.go | 2 +- txnprovider/txpool/pool.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/transaction_test_util.go b/tests/transaction_test_util.go index a78135aedce..8a1311ec214 100644 --- a/tests/transaction_test_util.go +++ b/tests/transaction_test_util.go @@ -78,7 +78,7 @@ func (tt *TransactionTest) Run(chainID *big.Int) error { if stx, ok := tx.(*types.SetCodeTransaction); ok { authorizationsLen = uint64(len(stx.GetAuthorizations())) } - requiredGas, err := core.IntrinsicGas(msg.Data(), msg.AccessList(), msg.To() == nil, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai, authorizationsLen) + requiredGas, err := core.IntrinsicGas(msg.Data(), msg.AccessList(), msg.To() == nil, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai, rules.IsPrague, authorizationsLen) if err != nil { return nil, nil, 0, err } diff --git a/txnprovider/txpool/pool.go b/txnprovider/txpool/pool.go index 9c1b22ce675..62d03a8c8a8 100644 --- a/txnprovider/txpool/pool.go +++ b/txnprovider/txpool/pool.go @@ -654,7 +654,7 @@ func (p *TxPool) best(ctx context.Context, n int, txns *TxnsRlp, onTopOf, availa best := p.pending.best isShanghai := p.isShanghai() || p.isAgra() - isPrague := p.isCancun() + isPrague := p.isPrague() txns.Resize(uint(min(n, len(best.ms)))) var toRemove []*metaTxn