mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-26 06:36:43 +00:00
feat(blobpool): add explicit max blob count limit
This commit is contained in:
parent
1f175347c4
commit
fa08c910fb
4 changed files with 79 additions and 9 deletions
|
|
@ -62,6 +62,12 @@ const (
|
|||
// limit can never hurt.
|
||||
txMaxSize = 1024 * 1024
|
||||
|
||||
// maxBlobsPerTx is the maximum number of blobs that a single transaction can
|
||||
// carry. We choose a smaller limit than the protocol-permitted MaxBlobsPerBlock
|
||||
// in order to ensure network and txpool stability.
|
||||
// Note: if you increase this, validation will fail on txMaxSize.
|
||||
maxBlobsPerTx = 7
|
||||
|
||||
// maxTxsPerAccount is the maximum number of blob transactions admitted from
|
||||
// a single account. The limit is enforced to minimize the DoS potential of
|
||||
// a private tx cancelling publicly propagated blobs.
|
||||
|
|
@ -1099,6 +1105,7 @@ func (p *BlobPool) ValidateTxBasics(tx *types.Transaction) error {
|
|||
Accept: 1 << types.BlobTxType,
|
||||
MaxSize: txMaxSize,
|
||||
MinTip: p.gasTip.ToBig(),
|
||||
MaxBlobCount: maxBlobsPerTx,
|
||||
}
|
||||
return txpool.ValidateTransaction(tx, p.head, p.signer, opts)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/holiman/billy"
|
||||
"github.com/holiman/uint256"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -1142,6 +1143,63 @@ func TestChangingSlotterSize(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// TestBlobCountLimit tests the blobpool enforced limits on the max blob count.
|
||||
func TestBlobCountLimit(t *testing.T) {
|
||||
// Create a temporary folder for the persistent backend
|
||||
storage := t.TempDir()
|
||||
|
||||
// Create transactions from a few accounts.
|
||||
var (
|
||||
key1, _ = crypto.GenerateKey()
|
||||
key2, _ = crypto.GenerateKey()
|
||||
|
||||
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
|
||||
|
||||
tx1 = makeMultiBlobTx(0, 1, 1000, 100, 7, key1)
|
||||
tx2 = makeMultiBlobTx(0, 1, 800, 70, 8, key2)
|
||||
)
|
||||
|
||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||
statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
|
||||
statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
|
||||
statedb.Commit(0, true, false)
|
||||
|
||||
// Make Prague-enabled custom chain config.
|
||||
cancunTime := uint64(0)
|
||||
pragueTime := uint64(0)
|
||||
config := ¶ms.ChainConfig{
|
||||
ChainID: big.NewInt(1),
|
||||
LondonBlock: big.NewInt(0),
|
||||
BerlinBlock: big.NewInt(0),
|
||||
CancunTime: &cancunTime,
|
||||
PragueTime: &pragueTime,
|
||||
BlobScheduleConfig: ¶ms.BlobScheduleConfig{
|
||||
Cancun: params.DefaultCancunBlobConfig,
|
||||
Prague: params.DefaultPragueBlobConfig,
|
||||
},
|
||||
}
|
||||
chain := &testBlockChain{
|
||||
config: config,
|
||||
basefee: uint256.NewInt(1050),
|
||||
blobfee: uint256.NewInt(105),
|
||||
statedb: statedb,
|
||||
}
|
||||
pool := New(Config{Datadir: storage}, chain, nil)
|
||||
if err := pool.Init(1, chain.CurrentBlock(), newReserver()); err != nil {
|
||||
t.Fatalf("failed to create blob pool: %v", err)
|
||||
}
|
||||
|
||||
// Attempt to add transactions.
|
||||
errs := pool.Add([]*types.Transaction{tx1, tx2}, true)
|
||||
assert.Equal(t, 2, len(errs))
|
||||
assert.NoError(t, errs[0])
|
||||
assert.EqualError(t, errs[1], "too many blobs in transaction: have 8, permitted 7")
|
||||
|
||||
verifyPoolInternals(t, pool)
|
||||
pool.Close()
|
||||
}
|
||||
|
||||
// Tests that adding transaction will correctly store it in the persistent store
|
||||
// and update all the indices.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -573,6 +573,7 @@ func (pool *LegacyPool) ValidateTxBasics(tx *types.Transaction) error {
|
|||
1<<types.SetCodeTxType,
|
||||
MaxSize: txMaxSize,
|
||||
MinTip: pool.gasTip.Load().ToBig(),
|
||||
MaxBlobCount: 0,
|
||||
}
|
||||
return txpool.ValidateTransaction(tx, pool.currentHead.Load(), pool.signer, opts)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ type ValidationOptions struct {
|
|||
|
||||
Accept uint8 // Bitmap of transaction types that should be accepted for the calling pool
|
||||
MaxSize uint64 // Maximum size of a transaction that the caller can meaningfully handle
|
||||
MaxBlobCount int // Maximum number of blobs allowed per transaction
|
||||
MinTip *big.Int // Minimum gas tip needed to allow a transaction into the caller pool
|
||||
}
|
||||
|
||||
|
|
@ -63,6 +64,9 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types
|
|||
if opts.Accept&(1<<tx.Type()) == 0 {
|
||||
return fmt.Errorf("%w: tx type %v not supported by this pool", core.ErrTxTypeNotSupported, tx.Type())
|
||||
}
|
||||
if blobCount := len(tx.BlobHashes()); blobCount > opts.MaxBlobCount {
|
||||
return fmt.Errorf("too many blobs in transaction: have %d, permitted %d", blobCount, opts.MaxBlobCount)
|
||||
}
|
||||
// Before performing any expensive validations, sanity check that the tx is
|
||||
// smaller than the maximum limit the pool can meaningfully handle
|
||||
if tx.Size() > opts.MaxSize {
|
||||
|
|
|
|||
Loading…
Reference in a new issue