diff --git a/core/state_transition.go b/core/state_transition.go index a23a26468e..271663d522 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -27,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto/kzg4844" + "github.com/ethereum/go-ethereum/objs" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" ) @@ -247,7 +248,8 @@ func (st *StateTransition) to() common.Address { } func (st *StateTransition) buyGas() error { - mgval := new(big.Int).SetUint64(st.msg.GasLimit) + mgval := objs.BigIntPool.Get().(*big.Int).SetUint64(st.msg.GasLimit) + defer objs.BigIntPool.Put(mgval) mgval = mgval.Mul(mgval, st.msg.GasPrice) var l1Cost *big.Int if st.evm.Context.L1CostFunc != nil && !st.msg.SkipAccountChecks { @@ -260,7 +262,8 @@ func (st *StateTransition) buyGas() error { mgval = mgval.Add(mgval, l1Cost) } } - balanceCheck := new(big.Int).Set(mgval) + balanceCheck := objs.BigIntPool.Get().(*big.Int).Set(mgval) + defer objs.BigIntPool.Put(balanceCheck) if st.msg.GasFeeCap != nil { balanceCheck.SetUint64(st.msg.GasLimit) balanceCheck = balanceCheck.Mul(balanceCheck, st.msg.GasFeeCap) @@ -272,7 +275,8 @@ func (st *StateTransition) buyGas() error { if st.evm.ChainConfig().IsCancun(st.evm.Context.BlockNumber, st.evm.Context.Time) { if blobGas := st.blobGasUsed(); blobGas > 0 { // Check that the user has enough funds to cover blobGasUsed * tx.BlobGasFeeCap - blobBalanceCheck := new(big.Int).SetUint64(blobGas) + blobBalanceCheck := objs.BigIntPool.Get().(*big.Int).SetUint64(blobGas) + defer objs.BigIntPool.Put(blobBalanceCheck) blobBalanceCheck.Mul(blobBalanceCheck, st.msg.BlobGasFeeCap) balanceCheck.Add(balanceCheck, blobBalanceCheck) // Pay for blobGasUsed * actual blob fee diff --git a/core/types/rollup_cost.go b/core/types/rollup_cost.go index e0bc26d92f..f784326267 100644 --- a/core/types/rollup_cost.go +++ b/core/types/rollup_cost.go @@ -24,6 +24,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/objs" "github.com/ethereum/go-ethereum/params" ) @@ -226,17 +227,23 @@ func newL1CostFuncEcotone(l1BaseFee, l1BlobBaseFee, l1BaseFeeScalar, l1BlobBaseF // // calldataGas*(l1BaseFee*16*l1BaseFeeScalar + l1BlobBaseFee*l1BlobBaseFeeScalar)/16e6 - calldataCostPerByte := new(big.Int).Set(l1BaseFee) + calldataCostPerByte := objs.BigIntPool.Get().(*big.Int) + calldataCostPerByte = calldataCostPerByte.Set(l1BaseFee) calldataCostPerByte = calldataCostPerByte.Mul(calldataCostPerByte, sixteen) calldataCostPerByte = calldataCostPerByte.Mul(calldataCostPerByte, l1BaseFeeScalar) - blobCostPerByte := new(big.Int).Set(l1BlobBaseFee) + blobCostPerByte := objs.BigIntPool.Get().(*big.Int) + blobCostPerByte = blobCostPerByte.Set(l1BlobBaseFee) blobCostPerByte = blobCostPerByte.Mul(blobCostPerByte, l1BlobBaseFeeScalar) fee = new(big.Int).Add(calldataCostPerByte, blobCostPerByte) fee = fee.Mul(fee, calldataGasUsed) fee = fee.Div(fee, ecotoneDivisor) + // recycle the two big.Int + objs.BigIntPool.Put(calldataCostPerByte) + objs.BigIntPool.Put(blobCostPerByte) + return fee, calldataGasUsed } } diff --git a/core/types/transaction.go b/core/types/transaction.go index d7860b57bd..0301592e66 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/objs" "github.com/ethereum/go-ethereum/rlp" ) @@ -307,6 +308,17 @@ func (tx *Transaction) GasFeeCap() *big.Int { return new(big.Int).Set(tx.inner.g // Value returns the ether amount of the transaction. func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.inner.value()) } +// Value returns the ether amount of the transaction. +func (tx *Transaction) ValueRef() *big.Int { return tx.inner.value() } + +// GasTipCap returns the gasTipCap per gas of the transaction. +func (tx *Transaction) GasTipCapRef() *big.Int { return tx.inner.gasTipCap() } + +// GasFeeCap returns the fee cap per gas of the transaction. +func (tx *Transaction) GasFeeCapRef() *big.Int { return tx.inner.gasFeeCap() } + +func (tx *Transaction) GasPriceRef() *big.Int { return tx.inner.gasPrice() } + // Nonce returns the sender account nonce of the transaction. func (tx *Transaction) Nonce() uint64 { return tx.inner.nonce() } @@ -362,11 +374,14 @@ func (tx *Transaction) IsSystemTx() bool { // Cost returns (gas * gasPrice) + (blobGas * blobGasPrice) + value. func (tx *Transaction) Cost() *big.Int { - total := new(big.Int).Mul(tx.GasPrice(), new(big.Int).SetUint64(tx.Gas())) + gasPrice := tx.inner.gasPrice() + gas := objs.BigIntPool.Get().(*big.Int).SetUint64(tx.Gas()) + total := new(big.Int).Mul(gasPrice, gas) if tx.Type() == BlobTxType { total.Add(total, new(big.Int).Mul(tx.BlobGasFeeCap(), new(big.Int).SetUint64(tx.BlobGas()))) } - total.Add(total, tx.Value()) + objs.BigIntPool.Put(gas) + total.Add(total, tx.inner.value()) return total } @@ -446,18 +461,27 @@ func (tx *Transaction) EffectiveGasTipCmp(other *Transaction, baseFee *big.Int) } // the EffectiveGasTipValue() always copies two big.Int, which cost almost 90% cpu resource of the whole function, // so we define an alternative function to improve the performance. - return effectiveGasTipValue(tx, baseFee).Cmp(effectiveGasTipValue(other, baseFee)) + effTx, recycleTx := effectiveGasTipValue(tx, baseFee) + effOther, recycleOther := effectiveGasTipValue(other, baseFee) + defer func() { + recycleTx() + recycleOther() + }() + return effTx.Cmp(effOther) } -func effectiveGasTipValue(tx *Transaction, baseFee *big.Int) *big.Int { +func effectiveGasTipValue(tx *Transaction, baseFee *big.Int) (*big.Int, func()) { if tx.Type() == DepositTxType { - return new(big.Int) + newInt := objs.BigIntPool.Get().(*big.Int) + newInt.SetUint64(0) + return newInt, func() { objs.BigIntPool.Put(newInt) } } if baseFee == nil { - return tx.inner.gasTipCap() + return tx.inner.gasTipCap(), func() {} } gasFeeCap := tx.inner.gasFeeCap() - return math.BigMin(tx.inner.gasTipCap(), new(big.Int).Sub(gasFeeCap, baseFee)) + temp := objs.BigIntPool.Get().(*big.Int).Sub(gasFeeCap, baseFee) + return math.BigMin(tx.inner.gasTipCap(), temp), func() { objs.BigIntPool.Put(temp) } } // EffectiveGasTipIntCmp compares the effective gasTipCap of a transaction to the given gasTipCap. diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 02fb0fdb7d..a44faa4464 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -2000,9 +2000,9 @@ func SubmitTransaction(ctx context.Context, b Backend, tx *types.Transaction) (c if tx.To() == nil { addr := crypto.CreateAddress(from, tx.Nonce()) - log.Info("Submitted contract creation", "hash", tx.Hash().Hex(), "from", from, "nonce", tx.Nonce(), "contract", addr.Hex(), "value", tx.Value()) + log.Info("Submitted contract creation", "hash", tx.Hash().Hex(), "from", from, "nonce", tx.Nonce(), "contract", addr.Hex(), "value", tx.ValueRef()) } else { - log.Info("Submitted transaction", "hash", tx.Hash().Hex(), "from", from, "nonce", tx.Nonce(), "recipient", tx.To(), "value", tx.Value()) + log.Info("Submitted transaction", "hash", tx.Hash().Hex(), "from", from, "nonce", tx.Nonce(), "recipient", tx.To(), "value", tx.ValueRef()) } return tx.Hash(), nil } diff --git a/objs/objpool.go b/objs/objpool.go new file mode 100644 index 0000000000..301a0a63c9 --- /dev/null +++ b/objs/objpool.go @@ -0,0 +1,14 @@ +package objs + +import ( + "math/big" + "sync" +) + +var ( + BigIntPool = sync.Pool{ + New: func() any { + return new(big.Int) + }, + } +)