diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go
index 75f1b65efa3046fc2079ff9a11fc8d738e303854..c5d2a12a7b26416bd0cabdde6d5fa68e0d30c031 100644
--- a/consensus/beacon/consensus.go
+++ b/consensus/beacon/consensus.go
@@ -257,7 +257,7 @@ func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, pa
 		return consensus.ErrInvalidNumber
 	}
 	// Verify the header's EIP-1559 attributes.
-	if err := misc.VerifyEip1559Header(chain.Config(), parent, header); err != nil {
+	if err := misc.VerifyEIP1559Header(chain.Config(), parent, header); err != nil {
 		return err
 	}
 	// Verify existence / non-existence of withdrawalsHash.
@@ -270,12 +270,17 @@ func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, pa
 	}
 	// Verify the existence / non-existence of excessDataGas
 	cancun := chain.Config().IsCancun(header.Number, header.Time)
-	if cancun && header.ExcessDataGas == nil {
-		return errors.New("missing excessDataGas")
-	}
 	if !cancun && header.ExcessDataGas != nil {
 		return fmt.Errorf("invalid excessDataGas: have %d, expected nil", header.ExcessDataGas)
 	}
+	if !cancun && header.DataGasUsed != nil {
+		return fmt.Errorf("invalid dataGasUsed: have %d, expected nil", header.DataGasUsed)
+	}
+	if cancun {
+		if err := misc.VerifyEIP4844Header(parent, header); err != nil {
+			return err
+		}
+	}
 	return nil
 }
 
diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go
index dd35e9d28bda0bbe046589f3074a301f118883d0..ee188206319de71f88e67c71c41aa87a6efa3887 100644
--- a/consensus/clique/clique.go
+++ b/consensus/clique/clique.go
@@ -343,7 +343,7 @@ func (c *Clique) verifyCascadingFields(chain consensus.ChainHeaderReader, header
 		if err := misc.VerifyGaslimit(parent.GasLimit, header.GasLimit); err != nil {
 			return err
 		}
-	} else if err := misc.VerifyEip1559Header(chain.Config(), parent, header); err != nil {
+	} else if err := misc.VerifyEIP1559Header(chain.Config(), parent, header); err != nil {
 		// Verify the header's EIP-1559 attributes.
 		return err
 	}
diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go
index acbbdacc3c715eeecd19a0b4a8c0c1f79b840d91..ad36f21ca9487f99b8fce487e2b70ec452510f2f 100644
--- a/consensus/ethash/consensus.go
+++ b/consensus/ethash/consensus.go
@@ -254,7 +254,7 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainHeaderReader, header, pa
 		if err := misc.VerifyGaslimit(parent.GasLimit, header.GasLimit); err != nil {
 			return err
 		}
-	} else if err := misc.VerifyEip1559Header(chain.Config(), parent, header); err != nil {
+	} else if err := misc.VerifyEIP1559Header(chain.Config(), parent, header); err != nil {
 		// Verify the header's EIP-1559 attributes.
 		return err
 	}
diff --git a/consensus/misc/eip1559.go b/consensus/misc/eip1559.go
index fbaf9eec76b22a0daa49893533027b289e5c0c40..2697f029e2d918a4b45138bbd96d1fd05e0ae508 100644
--- a/consensus/misc/eip1559.go
+++ b/consensus/misc/eip1559.go
@@ -27,10 +27,10 @@ import (
 	"github.com/ethereum/go-ethereum/params"
 )
 
-// VerifyEip1559Header verifies some header attributes which were changed in EIP-1559,
+// VerifyEIP1559Header verifies some header attributes which were changed in EIP-1559,
 // - gas limit check
 // - basefee check
-func VerifyEip1559Header(config *params.ChainConfig, parent, header *types.Header) error {
+func VerifyEIP1559Header(config *params.ChainConfig, parent, header *types.Header) error {
 	// Verify that the gas limit remains within allowed bounds
 	parentGasLimit := parent.GasLimit
 	if !config.IsLondon(parent.Number) {
diff --git a/consensus/misc/eip1559_test.go b/consensus/misc/eip1559_test.go
index 1a9f96bc432624ec2a539e30478dd80f77fd721e..59fded2cde709b9ad33683ad976b657a40dbf40f 100644
--- a/consensus/misc/eip1559_test.go
+++ b/consensus/misc/eip1559_test.go
@@ -95,7 +95,7 @@ func TestBlockGasLimits(t *testing.T) {
 			BaseFee:  initial,
 			Number:   big.NewInt(tc.pNum + 1),
 		}
-		err := VerifyEip1559Header(config(), parent, header)
+		err := VerifyEIP1559Header(config(), parent, header)
 		if tc.ok && err != nil {
 			t.Errorf("test %d: Expected valid header: %s", i, err)
 		}
diff --git a/consensus/misc/eip4844.go b/consensus/misc/eip4844.go
index 66ca9bd26d864d76881a3ba7090a69f572f5e0df..f370e490176acde5a727ed0131a845988aa5ccaa 100644
--- a/consensus/misc/eip4844.go
+++ b/consensus/misc/eip4844.go
@@ -17,8 +17,11 @@
 package misc
 
 import (
+	"errors"
+	"fmt"
 	"math/big"
 
+	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/params"
 )
 
@@ -27,13 +30,54 @@ var (
 	dataGaspriceUpdateFraction = big.NewInt(params.BlobTxDataGaspriceUpdateFraction)
 )
 
-// CalcBlobFee calculates the blobfee from the header's excess data gas field.
-func CalcBlobFee(excessDataGas *big.Int) *big.Int {
-	// If this block does not yet have EIP-4844 enabled, return the starting fee
-	if excessDataGas == nil {
-		return big.NewInt(params.BlobTxMinDataGasprice)
+// VerifyEIP4844Header verifies the presence of the excessDataGas field and that
+// if the current block contains no transactions, the excessDataGas is updated
+// accordingly.
+func VerifyEIP4844Header(parent, header *types.Header) error {
+	// Verify the header is not malformed
+	if header.ExcessDataGas == nil {
+		return errors.New("header is missing excessDataGas")
+	}
+	if header.DataGasUsed == nil {
+		return errors.New("header is missing dataGasUsed")
+	}
+	// Verify that the data gas used remains within reasonable limits.
+	if *header.DataGasUsed > params.BlobTxMaxDataGasPerBlock {
+		return fmt.Errorf("data gas used %d exceeds maximum allowance %d", *header.DataGasUsed, params.BlobTxMaxDataGasPerBlock)
+	}
+	if *header.DataGasUsed%params.BlobTxDataGasPerBlob != 0 {
+		return fmt.Errorf("data gas used %d not a multiple of data gas per blob %d", header.DataGasUsed, params.BlobTxDataGasPerBlob)
+	}
+	// Verify the excessDataGas is correct based on the parent header
+	var (
+		parentExcessDataGas uint64
+		parentDataGasUsed   uint64
+	)
+	if parent.ExcessDataGas != nil {
+		parentExcessDataGas = *parent.ExcessDataGas
+		parentDataGasUsed = *parent.DataGasUsed
 	}
-	return fakeExponential(minDataGasPrice, excessDataGas, dataGaspriceUpdateFraction)
+	expectedExcessDataGas := CalcExcessDataGas(parentExcessDataGas, parentDataGasUsed)
+	if *header.ExcessDataGas != expectedExcessDataGas {
+		return fmt.Errorf("invalid excessDataGas: have %d, want %d, parent excessDataGas %d, parent blobDataUsed %d",
+			*header.ExcessDataGas, expectedExcessDataGas, parentExcessDataGas, parentDataGasUsed)
+	}
+	return nil
+}
+
+// CalcExcessDataGas calculates the excess data gas after applying the set of
+// blobs on top of the excess data gas.
+func CalcExcessDataGas(parentExcessDataGas uint64, parentDataGasUsed uint64) uint64 {
+	excessDataGas := parentExcessDataGas + parentDataGasUsed
+	if excessDataGas < params.BlobTxTargetDataGasPerBlock {
+		return 0
+	}
+	return excessDataGas - params.BlobTxTargetDataGasPerBlock
+}
+
+// CalcBlobFee calculates the blobfee from the header's excess data gas field.
+func CalcBlobFee(excessDataGas uint64) *big.Int {
+	return fakeExponential(minDataGasPrice, new(big.Int).SetUint64(excessDataGas), dataGaspriceUpdateFraction)
 }
 
 // fakeExponential approximates factor * e ** (numerator / denominator) using
diff --git a/consensus/misc/eip4844_test.go b/consensus/misc/eip4844_test.go
index 5838cab8e669d0bb1717726c849930934966be47..939ca258700eb4e96e79d69826ce27d37b640f5a 100644
--- a/consensus/misc/eip4844_test.go
+++ b/consensus/misc/eip4844_test.go
@@ -24,9 +24,42 @@ import (
 	"github.com/ethereum/go-ethereum/params"
 )
 
+func TestCalcExcessDataGas(t *testing.T) {
+	var tests = []struct {
+		excess uint64
+		blobs  uint64
+		want   uint64
+	}{
+		// The excess data gas should not increase from zero if the used blob
+		// slots are below - or equal - to the target.
+		{0, 0, 0},
+		{0, 1, 0},
+		{0, params.BlobTxTargetDataGasPerBlock / params.BlobTxDataGasPerBlob, 0},
+
+		// If the target data gas is exceeded, the excessDataGas should increase
+		// by however much it was overshot
+		{0, (params.BlobTxTargetDataGasPerBlock / params.BlobTxDataGasPerBlob) + 1, params.BlobTxDataGasPerBlob},
+		{1, (params.BlobTxTargetDataGasPerBlock / params.BlobTxDataGasPerBlob) + 1, params.BlobTxDataGasPerBlob + 1},
+		{1, (params.BlobTxTargetDataGasPerBlock / params.BlobTxDataGasPerBlob) + 2, 2*params.BlobTxDataGasPerBlob + 1},
+
+		// The excess data gas should decrease by however much the target was
+		// under-shot, capped at zero.
+		{params.BlobTxTargetDataGasPerBlock, params.BlobTxTargetDataGasPerBlock / params.BlobTxDataGasPerBlob, params.BlobTxTargetDataGasPerBlock},
+		{params.BlobTxTargetDataGasPerBlock, (params.BlobTxTargetDataGasPerBlock / params.BlobTxDataGasPerBlob) - 1, params.BlobTxDataGasPerBlob},
+		{params.BlobTxTargetDataGasPerBlock, (params.BlobTxTargetDataGasPerBlock / params.BlobTxDataGasPerBlob) - 2, 0},
+		{params.BlobTxDataGasPerBlob - 1, (params.BlobTxTargetDataGasPerBlock / params.BlobTxDataGasPerBlob) - 1, 0},
+	}
+	for _, tt := range tests {
+		result := CalcExcessDataGas(tt.excess, tt.blobs*params.BlobTxDataGasPerBlob)
+		if result != tt.want {
+			t.Errorf("excess data gas mismatch: have %v, want %v", result, tt.want)
+		}
+	}
+}
+
 func TestCalcBlobFee(t *testing.T) {
 	tests := []struct {
-		excessDataGas int64
+		excessDataGas uint64
 		blobfee       int64
 	}{
 		{0, 1},
@@ -34,12 +67,8 @@ func TestCalcBlobFee(t *testing.T) {
 		{1542707, 2},
 		{10 * 1024 * 1024, 111},
 	}
-	have := CalcBlobFee(nil)
-	if have.Int64() != params.BlobTxMinDataGasprice {
-		t.Errorf("nil test: blobfee mismatch: have %v, want %v", have, params.BlobTxMinDataGasprice)
-	}
 	for i, tt := range tests {
-		have := CalcBlobFee(big.NewInt(tt.excessDataGas))
+		have := CalcBlobFee(tt.excessDataGas)
 		if have.Int64() != tt.blobfee {
 			t.Errorf("test %d: blobfee mismatch: have %v want %v", i, have, tt.blobfee)
 		}
diff --git a/core/block_validator.go b/core/block_validator.go
index fbd0d4bcf9eb0c0e1d5ff3062708e39630049a58..ce3e6560ee576a461b98244f57f0d4010ddf58ea 100644
--- a/core/block_validator.go
+++ b/core/block_validator.go
@@ -78,10 +78,23 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
 			return fmt.Errorf("withdrawals root hash mismatch (header value %x, calculated %x)", *header.WithdrawalsHash, hash)
 		}
 	} else if block.Withdrawals() != nil {
-		// Withdrawals are not allowed prior to shanghai fork
+		// Withdrawals are not allowed prior to Shanghai fork
 		return errors.New("withdrawals present in block body")
 	}
-
+	// Blob transactions may be present after the Cancun fork.
+	var blobs int
+	for _, tx := range block.Transactions() {
+		blobs += len(tx.BlobHashes())
+	}
+	if header.DataGasUsed != nil {
+		if want := *header.DataGasUsed / params.BlobTxDataGasPerBlob; uint64(blobs) != want { // div because the header is surely good vs the body might be bloated
+			return fmt.Errorf("data gas used mismatch (header %v, calculated %v)", *header.DataGasUsed, blobs*params.BlobTxDataGasPerBlob)
+		}
+	} else {
+		if blobs > 0 {
+			return errors.New("data blobs present in block body")
+		}
+	}
 	if !v.bc.HasBlockAndState(block.ParentHash(), block.NumberU64()-1) {
 		if !v.bc.HasBlock(block.ParentHash(), block.NumberU64()-1) {
 			return consensus.ErrUnknownAncestor
diff --git a/core/types/block.go b/core/types/block.go
index 58ea81676a804d6d463d1cb88c9684e145246c34..e1f1feb7a2ec373f43b53a649aadeeb7cd95cf33 100644
--- a/core/types/block.go
+++ b/core/types/block.go
@@ -86,19 +86,24 @@ type Header struct {
 	WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"`
 
 	// ExcessDataGas was added by EIP-4844 and is ignored in legacy headers.
-	ExcessDataGas *big.Int `json:"excessDataGas" rlp:"optional"`
+	ExcessDataGas *uint64 `json:"excessDataGas" rlp:"optional"`
+
+	// DataGasUsed was added by EIP-4844 and is ignored in legacy headers.
+	DataGasUsed *uint64 `json:"dataGasUsed" rlp:"optional"`
 }
 
 // field type overrides for gencodec
 type headerMarshaling struct {
-	Difficulty *hexutil.Big
-	Number     *hexutil.Big
-	GasLimit   hexutil.Uint64
-	GasUsed    hexutil.Uint64
-	Time       hexutil.Uint64
-	Extra      hexutil.Bytes
-	BaseFee    *hexutil.Big
-	Hash       common.Hash `json:"hash"` // adds call to Hash() in MarshalJSON
+	Difficulty    *hexutil.Big
+	Number        *hexutil.Big
+	GasLimit      hexutil.Uint64
+	GasUsed       hexutil.Uint64
+	Time          hexutil.Uint64
+	Extra         hexutil.Bytes
+	BaseFee       *hexutil.Big
+	Hash          common.Hash `json:"hash"` // adds call to Hash() in MarshalJSON
+	ExcessDataGas *hexutil.Uint64
+	DataGasUsed   *hexutil.Uint64
 }
 
 // Hash returns the block hash of the header, which is simply the keccak256 hash of its
@@ -146,10 +151,10 @@ func (h *Header) SanityCheck() error {
 // EmptyBody returns true if there is no additional 'body' to complete the header
 // that is: no transactions, no uncles and no withdrawals.
 func (h *Header) EmptyBody() bool {
-	if h.WithdrawalsHash == nil {
-		return h.TxHash == EmptyTxsHash && h.UncleHash == EmptyUncleHash
+	if h.WithdrawalsHash != nil {
+		return h.TxHash == EmptyTxsHash && *h.WithdrawalsHash == EmptyWithdrawalsHash
 	}
-	return h.TxHash == EmptyTxsHash && h.UncleHash == EmptyUncleHash && *h.WithdrawalsHash == EmptyWithdrawalsHash
+	return h.TxHash == EmptyTxsHash && h.UncleHash == EmptyUncleHash
 }
 
 // EmptyReceipts returns true if there are no receipts for this header/block.
@@ -347,6 +352,24 @@ func (b *Block) Withdrawals() Withdrawals {
 	return b.withdrawals
 }
 
+func (b *Block) ExcessDataGas() *uint64 {
+	var excessDataGas *uint64
+	if b.header.ExcessDataGas != nil {
+		excessDataGas = new(uint64)
+		*excessDataGas = *b.header.ExcessDataGas
+	}
+	return excessDataGas
+}
+
+func (b *Block) DataGasUsed() *uint64 {
+	var dataGasUsed *uint64
+	if b.header.DataGasUsed != nil {
+		dataGasUsed = new(uint64)
+		*dataGasUsed = *b.header.DataGasUsed
+	}
+	return dataGasUsed
+}
+
 func (b *Block) Header() *Header { return CopyHeader(b.header) }
 
 // Body returns the non-header content of the block.
diff --git a/core/types/gen_header_json.go b/core/types/gen_header_json.go
index 73287257bd1c74208a477e8bfae0fc58a36956c3..fe246d54ecd81c0ccbd7bd4889904950e9cc013d 100644
--- a/core/types/gen_header_json.go
+++ b/core/types/gen_header_json.go
@@ -16,25 +16,26 @@ var _ = (*headerMarshaling)(nil)
 // MarshalJSON marshals as JSON.
 func (h Header) MarshalJSON() ([]byte, error) {
 	type Header struct {
-		ParentHash      common.Hash    `json:"parentHash"       gencodec:"required"`
-		UncleHash       common.Hash    `json:"sha3Uncles"       gencodec:"required"`
-		Coinbase        common.Address `json:"miner"`
-		Root            common.Hash    `json:"stateRoot"        gencodec:"required"`
-		TxHash          common.Hash    `json:"transactionsRoot" gencodec:"required"`
-		ReceiptHash     common.Hash    `json:"receiptsRoot"     gencodec:"required"`
-		Bloom           Bloom          `json:"logsBloom"        gencodec:"required"`
-		Difficulty      *hexutil.Big   `json:"difficulty"       gencodec:"required"`
-		Number          *hexutil.Big   `json:"number"           gencodec:"required"`
-		GasLimit        hexutil.Uint64 `json:"gasLimit"         gencodec:"required"`
-		GasUsed         hexutil.Uint64 `json:"gasUsed"          gencodec:"required"`
-		Time            hexutil.Uint64 `json:"timestamp"        gencodec:"required"`
-		Extra           hexutil.Bytes  `json:"extraData"        gencodec:"required"`
-		MixDigest       common.Hash    `json:"mixHash"`
-		Nonce           BlockNonce     `json:"nonce"`
-		BaseFee         *hexutil.Big   `json:"baseFeePerGas" rlp:"optional"`
-		WithdrawalsHash *common.Hash   `json:"withdrawalsRoot" rlp:"optional"`
-		ExcessDataGas   *big.Int       `json:"excessDataGas" rlp:"optional"`
-		Hash            common.Hash    `json:"hash"`
+		ParentHash      common.Hash     `json:"parentHash"       gencodec:"required"`
+		UncleHash       common.Hash     `json:"sha3Uncles"       gencodec:"required"`
+		Coinbase        common.Address  `json:"miner"`
+		Root            common.Hash     `json:"stateRoot"        gencodec:"required"`
+		TxHash          common.Hash     `json:"transactionsRoot" gencodec:"required"`
+		ReceiptHash     common.Hash     `json:"receiptsRoot"     gencodec:"required"`
+		Bloom           Bloom           `json:"logsBloom"        gencodec:"required"`
+		Difficulty      *hexutil.Big    `json:"difficulty"       gencodec:"required"`
+		Number          *hexutil.Big    `json:"number"           gencodec:"required"`
+		GasLimit        hexutil.Uint64  `json:"gasLimit"         gencodec:"required"`
+		GasUsed         hexutil.Uint64  `json:"gasUsed"          gencodec:"required"`
+		Time            hexutil.Uint64  `json:"timestamp"        gencodec:"required"`
+		Extra           hexutil.Bytes   `json:"extraData"        gencodec:"required"`
+		MixDigest       common.Hash     `json:"mixHash"`
+		Nonce           BlockNonce      `json:"nonce"`
+		BaseFee         *hexutil.Big    `json:"baseFeePerGas" rlp:"optional"`
+		WithdrawalsHash *common.Hash    `json:"withdrawalsRoot" rlp:"optional"`
+		ExcessDataGas   *hexutil.Uint64 `json:"excessDataGas" rlp:"optional"`
+		DataGasUsed     *hexutil.Uint64 `json:"dataGasUsed" rlp:"optional"`
+		Hash            common.Hash     `json:"hash"`
 	}
 	var enc Header
 	enc.ParentHash = h.ParentHash
@@ -54,7 +55,8 @@ func (h Header) MarshalJSON() ([]byte, error) {
 	enc.Nonce = h.Nonce
 	enc.BaseFee = (*hexutil.Big)(h.BaseFee)
 	enc.WithdrawalsHash = h.WithdrawalsHash
-	enc.ExcessDataGas = h.ExcessDataGas
+	enc.ExcessDataGas = (*hexutil.Uint64)(h.ExcessDataGas)
+	enc.DataGasUsed = (*hexutil.Uint64)(h.DataGasUsed)
 	enc.Hash = h.Hash()
 	return json.Marshal(&enc)
 }
@@ -79,7 +81,8 @@ func (h *Header) UnmarshalJSON(input []byte) error {
 		Nonce           *BlockNonce     `json:"nonce"`
 		BaseFee         *hexutil.Big    `json:"baseFeePerGas" rlp:"optional"`
 		WithdrawalsHash *common.Hash    `json:"withdrawalsRoot" rlp:"optional"`
-		ExcessDataGas   *big.Int        `json:"excessDataGas" rlp:"optional"`
+		ExcessDataGas   *hexutil.Uint64 `json:"excessDataGas" rlp:"optional"`
+		DataGasUsed     *hexutil.Uint64 `json:"dataGasUsed" rlp:"optional"`
 	}
 	var dec Header
 	if err := json.Unmarshal(input, &dec); err != nil {
@@ -149,7 +152,10 @@ func (h *Header) UnmarshalJSON(input []byte) error {
 		h.WithdrawalsHash = dec.WithdrawalsHash
 	}
 	if dec.ExcessDataGas != nil {
-		h.ExcessDataGas = dec.ExcessDataGas
+		h.ExcessDataGas = (*uint64)(dec.ExcessDataGas)
+	}
+	if dec.DataGasUsed != nil {
+		h.DataGasUsed = (*uint64)(dec.DataGasUsed)
 	}
 	return nil
 }
diff --git a/core/types/gen_header_rlp.go b/core/types/gen_header_rlp.go
index 005f6c2ad45d8c2e5558f96409da5d7667dc60f3..f488931f1fb0012c5e8ee0150969391f1b252209 100644
--- a/core/types/gen_header_rlp.go
+++ b/core/types/gen_header_rlp.go
@@ -43,7 +43,8 @@ func (obj *Header) EncodeRLP(_w io.Writer) error {
 	_tmp1 := obj.BaseFee != nil
 	_tmp2 := obj.WithdrawalsHash != nil
 	_tmp3 := obj.ExcessDataGas != nil
-	if _tmp1 || _tmp2 || _tmp3 {
+	_tmp4 := obj.DataGasUsed != nil
+	if _tmp1 || _tmp2 || _tmp3 || _tmp4 {
 		if obj.BaseFee == nil {
 			w.Write(rlp.EmptyString)
 		} else {
@@ -53,21 +54,25 @@ func (obj *Header) EncodeRLP(_w io.Writer) error {
 			w.WriteBigInt(obj.BaseFee)
 		}
 	}
-	if _tmp2 || _tmp3 {
+	if _tmp2 || _tmp3 || _tmp4 {
 		if obj.WithdrawalsHash == nil {
 			w.Write([]byte{0x80})
 		} else {
 			w.WriteBytes(obj.WithdrawalsHash[:])
 		}
 	}
-	if _tmp3 {
+	if _tmp3 || _tmp4 {
 		if obj.ExcessDataGas == nil {
-			w.Write(rlp.EmptyString)
+			w.Write([]byte{0x80})
 		} else {
-			if obj.ExcessDataGas.Sign() == -1 {
-				return rlp.ErrNegativeBigInt
-			}
-			w.WriteBigInt(obj.ExcessDataGas)
+			w.WriteUint64((*obj.ExcessDataGas))
+		}
+	}
+	if _tmp4 {
+		if obj.DataGasUsed == nil {
+			w.Write([]byte{0x80})
+		} else {
+			w.WriteUint64((*obj.DataGasUsed))
 		}
 	}
 	w.ListEnd(_tmp0)
diff --git a/eth/downloader/queue.go b/eth/downloader/queue.go
index e9907297a0b93b037a1504fc6a59e2b2953a565e..0a00d48901cc115dd2cbf06e09570e1eb3d70c33 100644
--- a/eth/downloader/queue.go
+++ b/eth/downloader/queue.go
@@ -31,6 +31,7 @@ import (
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/log"
 	"github.com/ethereum/go-ethereum/metrics"
+	"github.com/ethereum/go-ethereum/params"
 )
 
 const (
@@ -796,6 +797,21 @@ func (q *queue) DeliverBodies(id string, txLists [][]*types.Transaction, txListH
 				return errInvalidBody
 			}
 		}
+		// Blocks must have a number of blobs corresponding to the header gas usage,
+		// and zero before the Cancun hardfork
+		var blobs int
+		for _, tx := range txLists[index] {
+			blobs += len(tx.BlobHashes())
+		}
+		if header.DataGasUsed != nil {
+			if want := *header.DataGasUsed / params.BlobTxDataGasPerBlob; uint64(blobs) != want { // div because the header is surely good vs the body might be bloated
+				return errInvalidBody
+			}
+		} else {
+			if blobs != 0 {
+				return errInvalidBody
+			}
+		}
 		return nil
 	}
 
diff --git a/params/protocol_params.go b/params/protocol_params.go
index 1fb258c1fc1ef5649858e271408a528c58694012..5ddc13c63b3e8194e21e35bf637711374cb14e4b 100644
--- a/params/protocol_params.go
+++ b/params/protocol_params.go
@@ -160,6 +160,8 @@ const (
 	RefundQuotient        uint64 = 2
 	RefundQuotientEIP3529 uint64 = 5
 
+	BlobTxMaxDataGasPerBlock         = 1 << 19 // Maximum consumable data gas for data blobs per block
+	BlobTxTargetDataGasPerBlock      = 1 << 18 // Target consumable data gas for data blobs per block (for 1559-like pricing)
 	BlobTxDataGasPerBlob             = 1 << 17 // Gas consumption of a single data blob (== blob byte size)
 	BlobTxMinDataGasprice            = 1       // Minimum gas price for data blobs
 	BlobTxDataGaspriceUpdateFraction = 2225652 // Controls the maximum rate of change for data gas price