Optimize BuildBlobSidecars Merkle proof computation by pre-computing subtrees (#15473)

* Optimize BuildBlobSidecars Merkle proof computation by pre-computing subtrees

Co-Authored-By: Claude <noreply@anthropic.com>

* Add change log

* Fix change log

---------

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
terence
2025-07-09 09:12:14 -07:00
committed by GitHub
parent f2d57f0b5f
commit f4f48d6372
4 changed files with 301 additions and 1 deletions

View File

@@ -25,6 +25,12 @@ var (
errInvalidInclusionProof = errors.New("invalid KZG commitment inclusion proof")
)
// MerkleProofComponents contains pre-computed components for efficient proof generation
type MerkleProofComponents struct {
kzgSubtree *trie.SparseMerkleTrie
topLevelProof [][]byte
}
// VerifyKZGInclusionProof verifies the Merkle proof in a Blob sidecar against
// the beacon block body root.
func VerifyKZGInclusionProof(blob ROBlob) error {
@@ -80,6 +86,67 @@ func MerkleProofKZGCommitment(body interfaces.ReadOnlyBeaconBlockBody, index int
return proof, nil
}
// PrecomputeMerkleProofComponents pre-computes the expensive parts of Merkle proof generation
// that are shared across all blob indices for a given block body.
func PrecomputeMerkleProofComponents(body interfaces.ReadOnlyBeaconBlockBody) (*MerkleProofComponents, error) {
bodyVersion := body.Version()
if bodyVersion < version.Deneb {
return nil, errUnsupportedBeaconBlockBody
}
// Pre-compute KZG subtree
commitments, err := body.BlobKzgCommitments()
if err != nil {
return nil, err
}
// No work needed if there are no commitments
if len(commitments) == 0 {
return nil, nil
}
leaves := LeavesFromCommitments(commitments)
kzgSubtree, err := trie.GenerateTrieFromItems(leaves, field_params.LogMaxBlobCommitments)
if err != nil {
return nil, err
}
// Pre-compute top-level components
membersRoots, err := topLevelRoots(body)
if err != nil {
return nil, err
}
topLevelTrie, err := trie.GenerateTrieFromItems(membersRoots, logBodyLength)
if err != nil {
return nil, err
}
topLevelProof, err := topLevelTrie.MerkleProof(kzgPosition)
if err != nil {
return nil, err
}
// Remove the last element that is not needed in topProof
topLevelProof = topLevelProof[:len(topLevelProof)-1]
return &MerkleProofComponents{
kzgSubtree: kzgSubtree,
topLevelProof: topLevelProof,
}, nil
}
// MerkleProofKZGCommitmentFromComponents constructs a Merkle proof for a specific index
// using pre-computed components, avoiding redundant calculations.
func MerkleProofKZGCommitmentFromComponents(components *MerkleProofComponents, index int) ([][]byte, error) {
// Generate index-specific proof from pre-computed KZG subtree
subtreeProof, err := components.kzgSubtree.MerkleProof(index)
if err != nil {
return nil, err
}
// Combine with pre-computed top-level proof
proof := append(subtreeProof, components.topLevelProof...)
return proof, nil
}
// MerkleProofKZGCommitments constructs a Merkle proof of inclusion of the KZG
// commitments into the Beacon Block with the given `body`
func MerkleProofKZGCommitments(body interfaces.ReadOnlyBeaconBlockBody) ([][]byte, error) {