From 6ec0a1ba7ce07a9c314a3de87d8b3e42ab1cc1df Mon Sep 17 00:00:00 2001 From: hexoscott <70711990+hexoscott@users.noreply.github.com> Date: Fri, 2 Dec 2022 15:32:56 +0000 Subject: [PATCH] txpool to consider available gas in Best call (#755) --- txpool/pool.go | 27 ++++++++++++++++++++++++--- txpool/txpool_grpc_server.go | 17 +++++++++-------- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/txpool/pool.go b/txpool/pool.go index 0983e5c0d..6c0305f78 100644 --- a/txpool/pool.go +++ b/txpool/pool.go @@ -34,6 +34,9 @@ import ( "github.com/google/btree" "github.com/hashicorp/golang-lru/simplelru" "github.com/holiman/uint256" + "github.com/ledgerwatch/log/v3" + "go.uber.org/atomic" + "github.com/ledgerwatch/erigon-lib/chain" "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon-lib/common/cmp" @@ -47,8 +50,6 @@ import ( "github.com/ledgerwatch/erigon-lib/kv/kvcache" "github.com/ledgerwatch/erigon-lib/kv/mdbx" "github.com/ledgerwatch/erigon-lib/types" - "github.com/ledgerwatch/log/v3" - "go.uber.org/atomic" ) var ( @@ -599,7 +600,7 @@ func (p *TxPool) Started() bool { return p.started.Load() } // Best - returns top `n` elements of pending queue // id doesn't perform full copy of txs, however underlying elements are immutable -func (p *TxPool) Best(n uint16, txs *types.TxsRlp, tx kv.Tx, onTopOf uint64) (bool, error) { +func (p *TxPool) Best(n uint16, txs *types.TxsRlp, tx kv.Tx, onTopOf, availableGas uint64) (bool, error) { // First wait for the corresponding block to arrive if p.lastSeenBlock.Load() < onTopOf { return false, nil // Too early @@ -615,6 +616,12 @@ func (p *TxPool) Best(n uint16, txs *types.TxsRlp, tx kv.Tx, onTopOf uint64) (bo best := p.pending.best for i := 0; j < int(n) && i < len(best.ms); i++ { + + // if we wouldn't have enough gas for a standard transaction then quit out early + if availableGas < fixedgas.TxGas { + break + } + mt := best.ms[i] if mt.Tx.Gas >= p.blockGasLimit.Load() { // Skip transactions with very large gas limit @@ -628,6 +635,20 @@ func (p *TxPool) Best(n uint16, txs *types.TxsRlp, tx kv.Tx, onTopOf uint64) (bo toRemove = append(toRemove, mt) continue } + + // make sure we have enough gas in the caller to add this transaction. + // not an exact science using intrinsic gas but as close as we could hope for at + // this stage + intrinsicGas, _ := CalcIntrinsicGas(uint64(mt.Tx.DataLen), uint64(mt.Tx.DataNonZeroLen), nil, mt.Tx.Creation, true, true) + if intrinsicGas > availableGas { + // we might find another TX with a low enough intrinsic gas to include so carry on + continue + } + + if intrinsicGas <= availableGas { // check for potential underflow + availableGas -= intrinsicGas + } + txs.Txs[j] = rlpTx copy(txs.Senders.At(j), sender) txs.IsLocal[j] = isLocal diff --git a/txpool/txpool_grpc_server.go b/txpool/txpool_grpc_server.go index 40ae62722..1c73a0813 100644 --- a/txpool/txpool_grpc_server.go +++ b/txpool/txpool_grpc_server.go @@ -28,12 +28,6 @@ import ( grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" grpc_recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery" "github.com/holiman/uint256" - "github.com/ledgerwatch/erigon-lib/common" - "github.com/ledgerwatch/erigon-lib/gointerfaces" - txpool_proto "github.com/ledgerwatch/erigon-lib/gointerfaces/txpool" - types2 "github.com/ledgerwatch/erigon-lib/gointerfaces/types" - "github.com/ledgerwatch/erigon-lib/kv" - "github.com/ledgerwatch/erigon-lib/types" "github.com/ledgerwatch/log/v3" "google.golang.org/grpc" "google.golang.org/grpc/credentials" @@ -42,6 +36,13 @@ import ( "google.golang.org/grpc/keepalive" "google.golang.org/grpc/reflection" "google.golang.org/protobuf/types/known/emptypb" + + "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon-lib/gointerfaces" + txpool_proto "github.com/ledgerwatch/erigon-lib/gointerfaces/txpool" + types2 "github.com/ledgerwatch/erigon-lib/gointerfaces/types" + "github.com/ledgerwatch/erigon-lib/kv" + "github.com/ledgerwatch/erigon-lib/types" ) // TxPoolAPIVersion @@ -50,7 +51,7 @@ var TxPoolAPIVersion = &types2.VersionReply{Major: 1, Minor: 0, Patch: 0} type txPool interface { ValidateSerializedTxn(serializedTxn []byte) error - Best(n uint16, txs *types.TxsRlp, tx kv.Tx, onTopOf uint64) (bool, error) + Best(n uint16, txs *types.TxsRlp, tx kv.Tx, onTopOf, availableGas uint64) (bool, error) GetRlp(tx kv.Tx, hash []byte) ([]byte, error) AddLocalTxs(ctx context.Context, newTxs types.TxSlots, tx kv.Tx) ([]DiscardReason, error) deprecatedForEach(_ context.Context, f func(rlp, sender []byte, t SubPoolType), tx kv.Tx) @@ -154,7 +155,7 @@ func (s *GrpcServer) Pending(ctx context.Context, _ *emptypb.Empty) (*txpool_pro reply := &txpool_proto.PendingReply{} reply.Txs = make([]*txpool_proto.PendingReply_Tx, 0, 32) txSlots := types.TxsRlp{} - if _, err := s.txPool.Best(math.MaxInt16, &txSlots, tx, 0 /* onTopOf */); err != nil { + if _, err := s.txPool.Best(math.MaxInt16, &txSlots, tx, 0 /* onTopOf */, math.MaxUint64 /* available gas */); err != nil { return nil, err } var senderArr [20]byte