Implement fulu related change to getblobsv1 and getpayloadv4

This commit is contained in:
Francis Li 2025-03-20 15:53:12 -07:00
parent 2e2eebe252
commit c4be2bbd19
No known key found for this signature in database
GPG key ID: 39F1A72C987F3F88
4 changed files with 100 additions and 13 deletions

View file

@ -116,11 +116,13 @@ type BlobsBundleV1 struct {
Commitments []hexutil.Bytes `json:"commitments"` Commitments []hexutil.Bytes `json:"commitments"`
Proofs []hexutil.Bytes `json:"proofs"` Proofs []hexutil.Bytes `json:"proofs"`
Blobs []hexutil.Bytes `json:"blobs"` Blobs []hexutil.Bytes `json:"blobs"`
CellProofs []hexutil.Bytes `json:"cellProofs"` // Added in Osaka for 7594
} }
type BlobAndProofV1 struct { type BlobAndProofV1 struct {
Blob hexutil.Bytes `json:"blob"` Blob hexutil.Bytes `json:"blob"`
Proof hexutil.Bytes `json:"proof"` Proof hexutil.Bytes `json:"proof"`
CellProofs []hexutil.Bytes `json:"cellProofs"` // Added in Osaka for 7594
} }
// JSON type overrides for ExecutionPayloadEnvelope. // JSON type overrides for ExecutionPayloadEnvelope.
@ -326,6 +328,7 @@ func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types.
Commitments: make([]hexutil.Bytes, 0), Commitments: make([]hexutil.Bytes, 0),
Blobs: make([]hexutil.Bytes, 0), Blobs: make([]hexutil.Bytes, 0),
Proofs: make([]hexutil.Bytes, 0), Proofs: make([]hexutil.Bytes, 0),
CellProofs: make([]hexutil.Bytes, 0),
} }
for _, sidecar := range sidecars { for _, sidecar := range sidecars {
for j := range sidecar.Blobs { for j := range sidecar.Blobs {

View file

@ -29,6 +29,8 @@ import (
"sync" "sync"
"time" "time"
gokzg4844 "github.com/crate-crypto/go-eth-kzg"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/misc/eip1559" "github.com/ethereum/go-ethereum/consensus/misc/eip1559"
"github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/consensus/misc/eip4844"
@ -1239,7 +1241,12 @@ func (p *BlobPool) GetRLP(hash common.Hash) []byte {
// GetBlobs returns a number of blobs are proofs for the given versioned hashes. // GetBlobs returns a number of blobs are proofs for the given versioned hashes.
// This is a utility method for the engine API, enabling consensus clients to // This is a utility method for the engine API, enabling consensus clients to
// retrieve blobs from the pools directly instead of the network. // retrieve blobs from the pools directly instead of the network.
// After Osaka, the proofs are returned as cell proofs.
func (p *BlobPool) GetBlobs(vhashes []common.Hash) ([]*kzg4844.Blob, []*kzg4844.Proof) { func (p *BlobPool) GetBlobs(vhashes []common.Hash) ([]*kzg4844.Blob, []*kzg4844.Proof) {
if p.chain.Config().IsOsaka(p.head.Number, p.head.Time) {
return p.GetBlobsWithCellProofs(vhashes)
}
// Create a map of the blob hash to indices for faster fills // Create a map of the blob hash to indices for faster fills
var ( var (
blobs = make([]*kzg4844.Blob, len(vhashes)) blobs = make([]*kzg4844.Blob, len(vhashes))
@ -1285,6 +1292,64 @@ func (p *BlobPool) GetBlobs(vhashes []common.Hash) ([]*kzg4844.Blob, []*kzg4844.
} }
} }
} }
return blobs, proofs
}
// GetBlobsWithCellProofs returns a number of blobs and cell proofs for the given versioned hashes after Osaka.
func (p *BlobPool) GetBlobsWithCellProofs(vhashes []common.Hash) ([]*kzg4844.Blob, []*kzg4844.Proof) {
var (
blobs = make([]*kzg4844.Blob, len(vhashes))
proofs = make([]*kzg4844.Proof, len(vhashes)*gokzg4844.CellsPerExtBlob)
)
index := make(map[common.Hash]int)
for i, vhash := range vhashes {
index[vhash] = i
}
for i, vhash := range vhashes {
if blobs[i] != nil {
continue
}
p.lock.RLock()
id, exists := p.lookup.storeidOfBlob(vhash)
if !exists {
p.lock.RUnlock()
continue
}
data, err := p.store.Get(id)
p.lock.RUnlock()
if err != nil {
log.Error("Tracked blob transaction missing from store", "id", id, "err", err)
continue
}
item := new(types.Transaction)
if err = rlp.DecodeBytes(data, item); err != nil {
log.Error("Blobs corrupted for traced transaction", "id", id, "err", err)
continue
}
sidecar := item.BlobTxSidecar()
if len(sidecar.Blobs)*gokzg4844.CellsPerExtBlob != len(sidecar.Proofs) {
log.Warn("potentially old blob tx with blob proofs, dropping it")
//TODO: implement dropping of blob txs
continue
}
for j, blobhash := range item.BlobHashes() {
if idx, ok := index[blobhash]; ok {
blobs[idx] = &sidecar.Blobs[j]
proofStart := idx * gokzg4844.CellsPerExtBlob
sidecarStart := j * gokzg4844.CellsPerExtBlob
for k := 0; k < gokzg4844.CellsPerExtBlob; k++ {
proofs[proofStart+k] = &sidecar.Proofs[sidecarStart+k]
}
}
}
}
return blobs, proofs return blobs, proofs
} }

View file

@ -169,7 +169,7 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types
func validateBlobSidecar(cfg *params.ChainConfig, time uint64, hashes []common.Hash, sidecar *types.BlobTxSidecar) error { func validateBlobSidecar(cfg *params.ChainConfig, time uint64, hashes []common.Hash, sidecar *types.BlobTxSidecar) error {
if len(sidecar.Blobs) != len(hashes) { if len(sidecar.Blobs) != len(hashes) {
return fmt.Errorf("invalid number of %d blobs compared to %d blob hashes", ErrInvalidBlobSidecar, len(sidecar.Blobs), len(hashes)) return fmt.Errorf("%w: invalid number of %d blobs compared to %d blob hashes", ErrInvalidBlobSidecar, len(sidecar.Blobs), len(hashes))
} }
if err := sidecar.ValidateBlobCommitmentHashes(hashes); err != nil { if err := sidecar.ValidateBlobCommitmentHashes(hashes); err != nil {
return err return err
@ -178,7 +178,7 @@ func validateBlobSidecar(cfg *params.ChainConfig, time uint64, hashes []common.H
fork := cfg.LatestFork(time) fork := cfg.LatestFork(time)
if fork >= forks.Osaka { if fork >= forks.Osaka {
if len(sidecar.Blobs)*gokzg4844.CellsPerExtBlob != len(sidecar.Proofs) { if len(sidecar.Blobs)*gokzg4844.CellsPerExtBlob != len(sidecar.Proofs) {
return fmt.Errorf("invalid number of %d cell proofs compared to %d blobs", ErrInvalidBlobSidecar, len(sidecar.Proofs), len(sidecar.Blobs)) return fmt.Errorf("%w: invalid number of %d cell proofs compared to %d blobs", ErrInvalidBlobSidecar, len(sidecar.Proofs), len(sidecar.Blobs))
} }
// Prepare cells and cell indices for each blob // Prepare cells and cell indices for each blob
@ -189,7 +189,7 @@ func validateBlobSidecar(cfg *params.ChainConfig, time uint64, hashes []common.H
// Compute cells for the currentblob // Compute cells for the currentblob
blobCells, err := kzg4844.ComputeCells(&sidecar.Blobs[i]) blobCells, err := kzg4844.ComputeCells(&sidecar.Blobs[i])
if err != nil { if err != nil {
return fmt.Errorf("failed to compute cells for blob %d: %v", ErrInvalidBlobSidecar, i, err) return fmt.Errorf("%w: failed to compute cells for blob %d: %v", ErrInvalidBlobSidecar, i, err)
} }
cells = append(cells, blobCells...) cells = append(cells, blobCells...)
@ -199,18 +199,18 @@ func validateBlobSidecar(cfg *params.ChainConfig, time uint64, hashes []common.H
} }
if err := kzg4844.VerifyCellKZGProofBatch(sidecar.Commitments, cellIndices, cells, sidecar.Proofs); err != nil { if err := kzg4844.VerifyCellKZGProofBatch(sidecar.Commitments, cellIndices, cells, sidecar.Proofs); err != nil {
return fmt.Errorf("failed to verify cell proofs: %v", ErrInvalidBlobSidecar, err) return fmt.Errorf("%w: failed to verify cell proofs: %v", ErrInvalidBlobSidecar, err)
} }
} else { // older folks } else { // older folks
if len(sidecar.Proofs) != len(hashes) { if len(sidecar.Proofs) != len(hashes) {
return fmt.Errorf("invalid number of %d blob proofs compared to %d blob hashes", ErrInvalidBlobSidecar, len(sidecar.Proofs), len(hashes)) return fmt.Errorf("%w: invalid number of %d blob proofs compared to %d blob hashes", ErrInvalidBlobSidecar, len(sidecar.Proofs), len(hashes))
} }
// Blob commitments match with the hashes in the transaction, verify the // Blob commitments match with the hashes in the transaction, verify the
// blobs themselves via KZG // blobs themselves via KZG
for i := range sidecar.Blobs { for i := range sidecar.Blobs {
if err := kzg4844.VerifyBlobProof(&sidecar.Blobs[i], sidecar.Commitments[i], sidecar.Proofs[i]); err != nil { if err := kzg4844.VerifyBlobProof(&sidecar.Blobs[i], sidecar.Commitments[i], sidecar.Proofs[i]); err != nil {
return fmt.Errorf("invalid blob %d: %v", ErrInvalidBlobSidecar, i, err) return fmt.Errorf("%w: invalid blob %d: %v", ErrInvalidBlobSidecar, i, err)
} }
} }
} }

View file

@ -24,6 +24,8 @@ import (
"sync" "sync"
"time" "time"
gokzg4844 "github.com/crate-crypto/go-eth-kzg"
"github.com/ethereum/go-ethereum/beacon/engine" "github.com/ethereum/go-ethereum/beacon/engine"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
@ -536,6 +538,21 @@ func (api *ConsensusAPI) GetBlobsV1(hashes []common.Hash) ([]*engine.BlobAndProo
res := make([]*engine.BlobAndProofV1, len(hashes)) res := make([]*engine.BlobAndProofV1, len(hashes))
blobs, proofs := api.eth.TxPool().GetBlobs(hashes) blobs, proofs := api.eth.TxPool().GetBlobs(hashes)
// after Osaka, the proofs are returned as cell proofs.
if len(blobs) != len(proofs) {
for i := range blobs {
if blobs[i] != nil {
cellProofs := make([]hexutil.Bytes, gokzg4844.CellsPerExtBlob)
for j := range cellProofs {
cellProofs[j] = hexutil.Bytes((*proofs[i*gokzg4844.CellsPerExtBlob+j])[:])
}
res[i] = &engine.BlobAndProofV1{
Blob: (*blobs[i])[:],
CellProofs: cellProofs,
}
}
}
} else {
for i := 0; i < len(blobs); i++ { for i := 0; i < len(blobs); i++ {
if blobs[i] != nil { if blobs[i] != nil {
res[i] = &engine.BlobAndProofV1{ res[i] = &engine.BlobAndProofV1{
@ -544,6 +561,8 @@ func (api *ConsensusAPI) GetBlobsV1(hashes []common.Hash) ([]*engine.BlobAndProo
} }
} }
} }
}
return res, nil return res, nil
} }