Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reuse big.Int objects for GC optimization #172

Draft
wants to merge 7 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions core/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand Down Expand Up @@ -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 {
Expand All @@ -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)
Expand All @@ -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
Expand Down
11 changes: 9 additions & 2 deletions core/types/rollup_cost.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand Down Expand Up @@ -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
}
}
Expand Down
38 changes: 31 additions & 7 deletions core/types/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand Down Expand Up @@ -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() }

Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions internal/ethapi/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
14 changes: 14 additions & 0 deletions objs/objpool.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package objs

import (
"math/big"
"sync"
)

var (
BigIntPool = sync.Pool{
New: func() any {
return new(big.Int)
},
}
)
Loading