diff --git a/core/error.go b/core/error.go index b9e894bd9b8..635d802863f 100644 --- a/core/error.go +++ b/core/error.go @@ -118,6 +118,9 @@ var ( // ErrMissingBlobHashes is returned if a blob transaction has no blob hashes. ErrMissingBlobHashes = errors.New("blob transaction missing blob hashes") + // ErrTooManyBlobs is returned if a blob transaction exceeds the maximum number of blobs. + ErrTooManyBlobs = errors.New("blob transaction has too many blobs") + // ErrBlobTxCreate is returned if a blob transaction has no explicit to field. ErrBlobTxCreate = errors.New("blob transaction of type create") diff --git a/core/state_transition.go b/core/state_transition.go index de4558253b5..681c3006965 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -354,6 +354,7 @@ func (st *stateTransition) preCheck() error { } } // Check the blob version validity + isOsaka := st.evm.ChainConfig().IsOsaka(st.evm.Context.BlockNumber, st.evm.Context.Time) if msg.BlobHashes != nil { // The to field of a blob tx type is mandatory, and a `BlobTx` transaction internally // has it as a non-nillable value, so any msg derived from blob transaction has it non-nil. @@ -364,6 +365,9 @@ func (st *stateTransition) preCheck() error { if len(msg.BlobHashes) == 0 { return ErrMissingBlobHashes } + if isOsaka && len(msg.BlobHashes) > params.BlobTxMaxBlobs { + return ErrTooManyBlobs + } for i, hash := range msg.BlobHashes { if !kzg4844.IsValidVersionedHash(hash[:]) { return fmt.Errorf("blob %d has invalid hash version", i) @@ -395,7 +399,7 @@ func (st *stateTransition) preCheck() error { } } // Verify tx gas limit does not exceed EIP-7825 cap. - if st.evm.ChainConfig().IsOsaka(st.evm.Context.BlockNumber, st.evm.Context.Time) && msg.GasLimit > params.MaxTxGas { + if isOsaka && msg.GasLimit > params.MaxTxGas { return fmt.Errorf("%w (cap: %d, tx: %d)", ErrGasLimitTooHigh, params.MaxTxGas, msg.GasLimit) } return st.buyGas() diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index 40429853f7b..078af34864b 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -65,7 +65,7 @@ const ( // 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 + maxBlobsPerTx = params.BlobTxMaxBlobs // maxTxsPerAccount is the maximum number of blob transactions admitted from // a single account. The limit is enforced to minimize the DoS potential of diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index ec1de6ef5da..422c35f6d2b 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -1191,8 +1191,8 @@ func TestBlobCountLimit(t *testing.T) { // Attempt to add transactions. var ( - tx1 = makeMultiBlobTx(0, 1, 1000, 100, 7, key1) - tx2 = makeMultiBlobTx(0, 1, 800, 70, 8, key2) + tx1 = makeMultiBlobTx(0, 1, 1000, 100, 6, key1) + tx2 = makeMultiBlobTx(0, 1, 800, 70, 7, key2) ) errs := pool.Add([]*types.Transaction{tx1, tx2}, true) diff --git a/params/protocol_params.go b/params/protocol_params.go index 3b48709a884..2ec3a5c2492 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -177,6 +177,7 @@ const ( BlobTxBlobGasPerBlob = 1 << 17 // Gas consumption of a single data blob (== blob byte size) BlobTxMinBlobGasprice = 1 // Minimum gas price for data blobs BlobTxPointEvaluationPrecompileGas = 50000 // Gas price for the point evaluation precompile. + BlobTxMaxBlobs = 6 BlobBaseCost = 1 << 13 // Base execution gas cost for a blob. HistoryServeWindow = 8192 // Number of blocks to serve historical block hashes for, EIP-2935.