feat: implement PayloadProof function (#14356)

* 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>
This commit is contained in:
Rupam Dey
2024-08-21 21:34:35 +05:30
committed by GitHub
parent ed3d7d49ec
commit 7c213ce161
6 changed files with 94 additions and 19 deletions

View File

@@ -14,21 +14,6 @@ import (
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
)
// ProofFromMerkleLayers creates a proof starting at the leaf index of the state Merkle layers.
func ProofFromMerkleLayers(layers [][][]byte, startingLeafIndex int) [][]byte {
// The merkle tree structure looks as follows:
// [[r1, r2, r3, r4], [parent1, parent2], [root]]
proof := make([][]byte, 0)
currentIndex := startingLeafIndex
for i := 0; i < len(layers)-1; i++ {
neighborIdx := currentIndex ^ 1
neighbor := layers[i][neighborIdx]
proof = append(proof, neighbor)
currentIndex = currentIndex / 2
}
return proof
}
func (f *FieldTrie) validateIndices(idxs []uint64) error {
length := f.length
if f.dataType == types.CompressedArray {

View File

@@ -67,6 +67,7 @@ go_library(
"//consensus-types/primitives:go_default_library",
"//container/multi-value-slice:go_default_library",
"//container/slice:go_default_library",
"//container/trie:go_default_library",
"//crypto/bls:go_default_library",
"//crypto/hash:go_default_library",
"//encoding/bytesutil:go_default_library",

View File

@@ -4,8 +4,8 @@ import (
"context"
"encoding/binary"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state/fieldtrie"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native/types"
"github.com/prysmaticlabs/prysm/v5/container/trie"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
)
@@ -56,7 +56,7 @@ func (b *BeaconState) CurrentSyncCommitteeProof(ctx context.Context) ([][]byte,
if err := b.recomputeDirtyFields(ctx); err != nil {
return nil, err
}
return fieldtrie.ProofFromMerkleLayers(b.merkleLayers, types.CurrentSyncCommittee.RealPosition()), nil
return trie.ProofFromMerkleLayers(b.merkleLayers, types.CurrentSyncCommittee.RealPosition()), nil
}
// NextSyncCommitteeProof from the state's Merkle trie representation.
@@ -74,7 +74,7 @@ func (b *BeaconState) NextSyncCommitteeProof(ctx context.Context) ([][]byte, err
if err := b.recomputeDirtyFields(ctx); err != nil {
return nil, err
}
return fieldtrie.ProofFromMerkleLayers(b.merkleLayers, types.NextSyncCommittee.RealPosition()), nil
return trie.ProofFromMerkleLayers(b.merkleLayers, types.NextSyncCommittee.RealPosition()), nil
}
// FinalizedRootProof crafts a Merkle proof for the finalized root
@@ -102,7 +102,7 @@ func (b *BeaconState) FinalizedRootProof(ctx context.Context) ([][]byte, error)
epochRoot := bytesutil.ToBytes32(epochBuf)
proof := make([][]byte, 0)
proof = append(proof, epochRoot[:])
branch := fieldtrie.ProofFromMerkleLayers(b.merkleLayers, types.FinalizedCheckpoint.RealPosition())
branch := trie.ProofFromMerkleLayers(b.merkleLayers, types.FinalizedCheckpoint.RealPosition())
proof = append(proof, branch...)
return proof, nil
}

View File

@@ -18,6 +18,7 @@ go_library(
importpath = "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks",
visibility = ["//visibility:public"],
deps = [
"//beacon-chain/state/stateutil:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//consensus-types:go_default_library",

View File

@@ -3,15 +3,23 @@ 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()
@@ -172,3 +180,68 @@ func ComputeBlockBodyFieldRoots(ctx context.Context, blockBody *BeaconBlockBody)
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
}

View File

@@ -259,3 +259,18 @@ func (m *SparseMerkleTrie) NumOfItems() int {
}
return len(m.originalItems)
}
// ProofFromMerkleLayers creates a proof starting at the leaf index of the merkle layers.
func ProofFromMerkleLayers(layers [][][]byte, startingLeafIndex int) [][]byte {
// The merkle tree structure looks as follows:
// [[r1, r2, r3, r4], [parent1, parent2], [root]]
proof := make([][]byte, 0)
currentIndex := startingLeafIndex
for i := 0; i < len(layers)-1; i++ {
neighborIdx := currentIndex ^ 1
neighbor := layers[i][neighborIdx]
proof = append(proof, neighbor)
currentIndex = currentIndex / 2
}
return proof
}