mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-08 23:18:15 -05:00
* feat: implement function `PayloadProof` to calculate proof of execution payload * remove comments * feat: implement function to compute field roots of * feat: implement function to compute `BeaconBlock` field roots and add tests * fix dependencies * check if interface implements the assserted type * fix: lint * replace `ok != true` with `!ok` * remove unused parameter from `PayloadProof` * remove test and move `PayloadProof` to `blocks/proofs.go` * remove `PayloadProof` from `fieldtrie` * replace `fieldtrie.ProofFromMerkleLayers` with `trie.ProofFromMerkleLayers` * Update container/trie/sparse_merkle.go * update dependencies --------- Co-authored-by: Radosław Kapka <rkapka@wp.pl> Co-authored-by: Radosław Kapka <radoslaw.kapka@gmail.com>
248 lines
6.0 KiB
Go
248 lines
6.0 KiB
Go
package blocks
|
|
|
|
import (
|
|
"context"
|
|
"encoding/binary"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state/stateutil"
|
|
"github.com/prysmaticlabs/prysm/v5/config/params"
|
|
"github.com/prysmaticlabs/prysm/v5/container/trie"
|
|
"github.com/prysmaticlabs/prysm/v5/crypto/hash/htr"
|
|
"github.com/prysmaticlabs/prysm/v5/encoding/ssz"
|
|
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
|
"go.opencensus.io/trace"
|
|
)
|
|
|
|
const (
|
|
payloadFieldIndex = 9
|
|
bodyFieldIndex = 4
|
|
)
|
|
|
|
func ComputeBlockBodyFieldRoots(ctx context.Context, blockBody *BeaconBlockBody) ([][]byte, error) {
|
|
_, span := trace.StartSpan(ctx, "blocks.ComputeBlockBodyFieldRoots")
|
|
defer span.End()
|
|
|
|
if blockBody == nil {
|
|
return nil, errNilBlockBody
|
|
}
|
|
|
|
var fieldRoots [][]byte
|
|
switch blockBody.version {
|
|
case version.Phase0:
|
|
fieldRoots = make([][]byte, 8)
|
|
case version.Altair:
|
|
fieldRoots = make([][]byte, 9)
|
|
case version.Bellatrix:
|
|
fieldRoots = make([][]byte, 10)
|
|
case version.Capella:
|
|
fieldRoots = make([][]byte, 11)
|
|
case version.Deneb:
|
|
fieldRoots = make([][]byte, 12)
|
|
case version.Electra:
|
|
fieldRoots = make([][]byte, 12)
|
|
default:
|
|
return nil, fmt.Errorf("unknown block body version %s", version.String(blockBody.version))
|
|
}
|
|
|
|
for i := range fieldRoots {
|
|
fieldRoots[i] = make([]byte, 32)
|
|
}
|
|
|
|
// Randao Reveal
|
|
randao := blockBody.RandaoReveal()
|
|
root, err := ssz.MerkleizeByteSliceSSZ(randao[:])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
copy(fieldRoots[0], root[:])
|
|
|
|
// eth1_data
|
|
eth1 := blockBody.Eth1Data()
|
|
root, err = eth1.HashTreeRoot()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
copy(fieldRoots[1], root[:])
|
|
|
|
// graffiti
|
|
root = blockBody.Graffiti()
|
|
copy(fieldRoots[2], root[:])
|
|
|
|
// Proposer slashings
|
|
ps := blockBody.ProposerSlashings()
|
|
root, err = ssz.MerkleizeListSSZ(ps, params.BeaconConfig().MaxProposerSlashings)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
copy(fieldRoots[3], root[:])
|
|
|
|
// Attester slashings
|
|
as := blockBody.AttesterSlashings()
|
|
bodyVersion := blockBody.Version()
|
|
if bodyVersion < version.Electra {
|
|
root, err = ssz.MerkleizeListSSZ(as, params.BeaconConfig().MaxAttesterSlashings)
|
|
} else {
|
|
root, err = ssz.MerkleizeListSSZ(as, params.BeaconConfig().MaxAttesterSlashingsElectra)
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
copy(fieldRoots[4], root[:])
|
|
|
|
// Attestations
|
|
att := blockBody.Attestations()
|
|
if bodyVersion < version.Electra {
|
|
root, err = ssz.MerkleizeListSSZ(att, params.BeaconConfig().MaxAttestations)
|
|
} else {
|
|
root, err = ssz.MerkleizeListSSZ(att, params.BeaconConfig().MaxAttestationsElectra)
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
copy(fieldRoots[5], root[:])
|
|
|
|
// Deposits
|
|
dep := blockBody.Deposits()
|
|
root, err = ssz.MerkleizeListSSZ(dep, params.BeaconConfig().MaxDeposits)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
copy(fieldRoots[6], root[:])
|
|
|
|
// Voluntary Exits
|
|
ve := blockBody.VoluntaryExits()
|
|
root, err = ssz.MerkleizeListSSZ(ve, params.BeaconConfig().MaxVoluntaryExits)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
copy(fieldRoots[7], root[:])
|
|
|
|
if blockBody.version >= version.Altair {
|
|
// Sync Aggregate
|
|
sa, err := blockBody.SyncAggregate()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
root, err = sa.HashTreeRoot()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
copy(fieldRoots[8], root[:])
|
|
}
|
|
|
|
if blockBody.version >= version.Bellatrix {
|
|
// Execution Payload
|
|
ep, err := blockBody.Execution()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
root, err = ep.HashTreeRoot()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
copy(fieldRoots[9], root[:])
|
|
}
|
|
|
|
if blockBody.version >= version.Capella {
|
|
// BLS Changes
|
|
bls, err := blockBody.BLSToExecutionChanges()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
root, err = ssz.MerkleizeListSSZ(bls, params.BeaconConfig().MaxBlsToExecutionChanges)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
copy(fieldRoots[10], root[:])
|
|
}
|
|
|
|
if blockBody.version >= version.Deneb {
|
|
// KZG commitments
|
|
roots := make([][32]byte, len(blockBody.blobKzgCommitments))
|
|
for i, commitment := range blockBody.blobKzgCommitments {
|
|
chunks, err := ssz.PackByChunk([][]byte{commitment})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
roots[i] = htr.VectorizedSha256(chunks)[0]
|
|
}
|
|
commitmentsRoot, err := ssz.BitwiseMerkleize(roots, uint64(len(roots)), 4096)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
length := make([]byte, 32)
|
|
binary.LittleEndian.PutUint64(length[:8], uint64(len(roots)))
|
|
root = ssz.MixInLength(commitmentsRoot, length)
|
|
copy(fieldRoots[11], root[:])
|
|
}
|
|
|
|
return fieldRoots, nil
|
|
}
|
|
|
|
func ComputeBlockFieldRoots(ctx context.Context, block *BeaconBlock) ([][]byte, error) {
|
|
_, span := trace.StartSpan(ctx, "blocks.ComputeBlockFieldRoots")
|
|
defer span.End()
|
|
|
|
if block == nil {
|
|
return nil, errNilBlock
|
|
}
|
|
|
|
fieldRoots := make([][]byte, 5)
|
|
for i := range fieldRoots {
|
|
fieldRoots[i] = make([]byte, 32)
|
|
}
|
|
|
|
// Slot
|
|
slotRoot := ssz.Uint64Root(uint64(block.slot))
|
|
copy(fieldRoots[0], slotRoot[:])
|
|
|
|
// Proposer Index
|
|
proposerRoot := ssz.Uint64Root(uint64(block.proposerIndex))
|
|
copy(fieldRoots[1], proposerRoot[:])
|
|
|
|
// Parent Root
|
|
copy(fieldRoots[2], block.parentRoot[:])
|
|
|
|
// State Root
|
|
copy(fieldRoots[3], block.stateRoot[:])
|
|
|
|
// block body Root
|
|
blockBodyRoot, err := block.body.HashTreeRoot()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
copy(fieldRoots[4], blockBodyRoot[:])
|
|
|
|
return fieldRoots, nil
|
|
}
|
|
|
|
func PayloadProof(ctx context.Context, block *BeaconBlock) ([][]byte, error) {
|
|
i := block.Body()
|
|
blockBody, ok := i.(*BeaconBlockBody)
|
|
if !ok {
|
|
return nil, errors.New("failed to cast block body")
|
|
}
|
|
|
|
blockBodyFieldRoots, err := ComputeBlockBodyFieldRoots(ctx, blockBody)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
blockBodyFieldRootsTrie := stateutil.Merkleize(blockBodyFieldRoots)
|
|
blockBodyProof := trie.ProofFromMerkleLayers(blockBodyFieldRootsTrie, payloadFieldIndex)
|
|
|
|
beaconBlockFieldRoots, err := ComputeBlockFieldRoots(ctx, block)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
beaconBlockFieldRootsTrie := stateutil.Merkleize(beaconBlockFieldRoots)
|
|
beaconBlockProof := trie.ProofFromMerkleLayers(beaconBlockFieldRootsTrie, bodyFieldIndex)
|
|
|
|
finalProof := append(blockBodyProof, beaconBlockProof...)
|
|
|
|
return finalProof, nil
|
|
}
|