@@ -138,28 +138,7 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types
138138 return fmt .Errorf ("%w: gas tip cap %v, minimum needed %v" , ErrTxGasPriceTooLow , tx .GasTipCap (), opts .MinTip )
139139 }
140140 if tx .Type () == types .BlobTxType {
141- // Ensure the blob fee cap satisfies the minimum blob gas price
142- if tx .BlobGasFeeCapIntCmp (blobTxMinBlobGasPrice ) < 0 {
143- return fmt .Errorf ("%w: blob fee cap %v, minimum needed %v" , ErrTxGasPriceTooLow , tx .BlobGasFeeCap (), blobTxMinBlobGasPrice )
144- }
145- sidecar := tx .BlobTxSidecar ()
146- if sidecar == nil {
147- return errors .New ("missing sidecar in blob transaction" )
148- }
149- // Ensure the number of items in the blob transaction and various side
150- // data match up before doing any expensive validations
151- hashes := tx .BlobHashes ()
152- if len (hashes ) == 0 {
153- return errors .New ("blobless blob transaction" )
154- }
155- maxBlobs := eip4844 .MaxBlobsPerBlock (opts .Config , head .Time )
156- if len (hashes ) > maxBlobs {
157- return fmt .Errorf ("too many blobs in transaction: have %d, permitted %d" , len (hashes ), maxBlobs )
158- }
159- // Ensure commitments, proofs and hashes are valid
160- if err := validateBlobSidecar (hashes , sidecar ); err != nil {
161- return err
162- }
141+ return validateBlobTx (tx , head , opts )
163142 }
164143 if tx .Type () == types .SetCodeTxType {
165144 if len (tx .SetCodeAuthorizations ()) == 0 {
@@ -169,18 +148,46 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types
169148 return nil
170149}
171150
172- func validateBlobSidecar (hashes []common.Hash , sidecar * types.BlobTxSidecar ) error {
151+ // validateBlobTx implements the blob-transaction specific validations.
152+ func validateBlobTx (tx * types.Transaction , head * types.Header , opts * ValidationOptions ) error {
153+ sidecar := tx .BlobTxSidecar ()
154+ if sidecar == nil {
155+ return errors .New ("missing sidecar in blob transaction" )
156+ }
157+ // Ensure the blob fee cap satisfies the minimum blob gas price
158+ if tx .BlobGasFeeCapIntCmp (blobTxMinBlobGasPrice ) < 0 {
159+ return fmt .Errorf ("%w: blob fee cap %v, minimum needed %v" , ErrTxGasPriceTooLow , tx .BlobGasFeeCap (), blobTxMinBlobGasPrice )
160+ }
161+ // Ensure the number of items in the blob transaction and various side
162+ // data match up before doing any expensive validations
163+ hashes := tx .BlobHashes ()
164+ if len (hashes ) == 0 {
165+ return errors .New ("blobless blob transaction" )
166+ }
167+ maxBlobs := eip4844 .MaxBlobsPerBlock (opts .Config , head .Time )
168+ if len (hashes ) > maxBlobs {
169+ return fmt .Errorf ("too many blobs in transaction: have %d, permitted %d" , len (hashes ), maxBlobs )
170+ }
173171 if len (sidecar .Blobs ) != len (hashes ) {
174172 return fmt .Errorf ("invalid number of %d blobs compared to %d blob hashes" , len (sidecar .Blobs ), len (hashes ))
175173 }
176- if len (sidecar .Proofs ) != len (hashes ) {
177- return fmt .Errorf ("invalid number of %d blob proofs compared to %d blob hashes" , len (sidecar .Proofs ), len (hashes ))
178- }
179174 if err := sidecar .ValidateBlobCommitmentHashes (hashes ); err != nil {
180175 return err
181176 }
182- // Blob commitments match with the hashes in the transaction, verify the
183- // blobs themselves via KZG
177+ // Fork-specific sidecar checks, including proof verification.
178+ if opts .Config .IsOsaka (head .Number , head .Time ) {
179+ return validateBlobSidecarOsaka (sidecar , hashes )
180+ }
181+ return validateBlobSidecarLegacy (sidecar , hashes )
182+ }
183+
184+ func validateBlobSidecarLegacy (sidecar * types.BlobTxSidecar , hashes []common.Hash ) error {
185+ if sidecar .Version != 0 {
186+ return fmt .Errorf ("invalid sidecar version pre-osaka: %v" , sidecar .Version )
187+ }
188+ if len (sidecar .Proofs ) != len (hashes ) {
189+ return fmt .Errorf ("invalid number of %d blob proofs expected %d" , len (sidecar .Proofs ), len (hashes ))
190+ }
184191 for i := range sidecar .Blobs {
185192 if err := kzg4844 .VerifyBlobProof (& sidecar .Blobs [i ], sidecar .Commitments [i ], sidecar .Proofs [i ]); err != nil {
186193 return fmt .Errorf ("invalid blob %d: %v" , i , err )
@@ -189,6 +196,16 @@ func validateBlobSidecar(hashes []common.Hash, sidecar *types.BlobTxSidecar) err
189196 return nil
190197}
191198
199+ func validateBlobSidecarOsaka (sidecar * types.BlobTxSidecar , hashes []common.Hash ) error {
200+ if sidecar .Version != 1 {
201+ return fmt .Errorf ("invalid sidecar version post-osaka: %v" , sidecar .Version )
202+ }
203+ if len (sidecar .Proofs ) != len (hashes )* kzg4844 .CellProofsPerBlob {
204+ return fmt .Errorf ("invalid number of %d blob proofs expected %d" , len (sidecar .Proofs ), len (hashes )* kzg4844 .CellProofsPerBlob )
205+ }
206+ return kzg4844 .VerifyCellProofs (sidecar .Blobs , sidecar .Commitments , sidecar .Proofs )
207+ }
208+
192209// ValidationOptionsWithState define certain differences between stateful transaction
193210// validation across the different pools without having to duplicate those checks.
194211type ValidationOptionsWithState struct {
0 commit comments