Skip to content

Commit

Permalink
Support for signed beacon block header and signature verification (be…
Browse files Browse the repository at this point in the history
…rachain#2245)

Co-authored-by: Giuseppe Cocomazzi <[email protected]>
  • Loading branch information
sbudella-gco and Giuseppe Cocomazzi authored Dec 17, 2024
1 parent 98d1225 commit 5246cf5
Show file tree
Hide file tree
Showing 20 changed files with 549 additions and 68 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ site/
contracts/cache
contracts/out
tmp/
cscope.files

##########
# Golang #
Expand Down
24 changes: 22 additions & 2 deletions beacon/blockchain/process_proposal.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ func (s *Service[
return createProcessProposalResponse(errors.WrapNonFatal(err))
}

// In theory, swapping the order of verification between the sidecars
// and the incoming block should not introduce any inconsistencies
// in the state on which the sidecar verification depends on (notably
// the currently active fork). ProcessProposal should only
// keep the state changes as candidates (which is what we do in
// VerifyIncomingBlock).

// Process the blob sidecars, if any
if !sidecars.IsNil() && sidecars.Len() > 0 {
var consensusSidecars *types.ConsensusSidecars[BlobSidecarsT]
Expand All @@ -83,13 +90,26 @@ func (s *Service[
s.logger.Info("Received incoming blob sidecars")

// TODO: Clean this up once we remove generics.
c := convertConsensusSidecars[
cs := convertConsensusSidecars[
ConsensusSidecarsT,
BlobSidecarsT,
](consensusSidecars)

// Get the sidecar verification function from the state processor
//nolint:govet // err shadowing
sidecarVerifierFn, err := s.stateProcessor.GetSidecarVerifierFn(
s.storageBackend.StateFromContext(ctx),
)
if err != nil {
s.logger.Error(
"an error incurred while calculating the sidecar verifier",
"reason", err,
)
return createProcessProposalResponse(errors.WrapNonFatal(err))
}

// Verify the blobs and ensure they match the local state.
err = s.blobProcessor.VerifySidecars(c)
err = s.blobProcessor.VerifySidecars(cs, sidecarVerifierFn)
if err != nil {
s.logger.Error(
"rejecting incoming blob sidecars",
Expand Down
6 changes: 4 additions & 2 deletions beacon/blockchain/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ type Service[
]
blobProcessor da.BlobProcessor[
AvailabilityStoreT,
ConsensusSidecarsT, BlobSidecarsT,
ConsensusSidecarsT,
BlobSidecarsT,
]
// store is the block store for the service.
// TODO: Remove this and use the block store from the storage backend.
Expand Down Expand Up @@ -143,7 +144,8 @@ func NewService[
],
blobProcessor da.BlobProcessor[
AvailabilityStoreT,
ConsensusSidecarsT, BlobSidecarsT,
ConsensusSidecarsT,
BlobSidecarsT,
],
blockStore BlockStoreT,
depositStore deposit.Store,
Expand Down
7 changes: 7 additions & 0 deletions beacon/blockchain/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives"
"github.com/berachain/beacon-kit/primitives/common"
"github.com/berachain/beacon-kit/primitives/constraints"
"github.com/berachain/beacon-kit/primitives/crypto"
"github.com/berachain/beacon-kit/primitives/math"
"github.com/berachain/beacon-kit/primitives/transition"
cmtabci "github.com/cometbft/cometbft/abci/types"
Expand Down Expand Up @@ -209,6 +210,12 @@ type StateProcessor[
BeaconStateT,
BeaconBlockT,
) (transition.ValidatorUpdates, error)
GetSidecarVerifierFn(BeaconStateT) (
func(
blkHeader *ctypes.BeaconBlockHeader,
signature crypto.BLSSignature) error,
error,
)
}

// StorageBackend defines an interface for accessing various storage components
Expand Down
49 changes: 38 additions & 11 deletions beacon/validator/block_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ func (s *Service[
ctx context.Context,
slotData types.SlotData[ctypes.SlashingInfo],
) ([]byte, []byte, error) {
var (
blk BeaconBlockT
sidecars BlobSidecarsT
forkData *ctypes.ForkData
)

startTime := time.Now()
defer s.metrics.measureRequestBlockForProposalTime(startTime)

Expand All @@ -65,15 +71,21 @@ func (s *Service[
return nil, nil, err
}

// Build forkdata used for the signing root of the reveal and the sidecars
forkData, err := s.buildForkData(st, slotData.GetSlot())
if err != nil {
return nil, nil, err
}

// Build the reveal for the current slot.
// TODO: We can optimize to pre-compute this in parallel?
reveal, err := s.buildRandaoReveal(st, slotData.GetSlot())
reveal, err := s.buildRandaoReveal(forkData, slotData.GetSlot())
if err != nil {
return nil, nil, err
}

// Create a new empty block from the current state.
blk, err := s.getEmptyBeaconBlockForSlot(st, slotData.GetSlot())
blk, err = s.getEmptyBeaconBlockForSlot(st, slotData.GetSlot())
if err != nil {
return nil, nil, err
}
Expand Down Expand Up @@ -107,8 +119,12 @@ func (s *Service[
}

// Produce blob sidecars with new StateRoot
sidecars, err := s.blobFactory.BuildSidecars(
blk, envelope.GetBlobsBundle())
sidecars, err = s.blobFactory.BuildSidecars(
blk,
envelope.GetBlobsBundle(),
s.signer,
forkData,
)
if err != nil {
return nil, nil, err
}
Expand Down Expand Up @@ -164,27 +180,38 @@ func (s *Service[
)
}

// buildRandaoReveal builds a randao reveal for the given slot.
func (s *Service[
_, _, BeaconStateT, _, _, _, _, _, _, _,
]) buildRandaoReveal(
]) buildForkData(
st BeaconStateT,
slot math.Slot,
) (crypto.BLSSignature, error) {
) (*ctypes.ForkData, error) {
var (
epoch = s.chainSpec.SlotToEpoch(slot)
)

genesisValidatorsRoot, err := st.GetGenesisValidatorsRoot()
if err != nil {
return crypto.BLSSignature{}, err
return nil, err
}

signingRoot := ctypes.NewForkData(
return ctypes.NewForkData(
version.FromUint32[common.Version](
s.chainSpec.ActiveForkVersionForEpoch(epoch),
), genesisValidatorsRoot,
).ComputeRandaoSigningRoot(
),
genesisValidatorsRoot,
), nil
}

// buildRandaoReveal builds a randao reveal for the given slot.
func (s *Service[
_, _, BeaconStateT, _, _, _, _, _, _, _,
]) buildRandaoReveal(
forkData *ctypes.ForkData,
slot math.Slot,
) (crypto.BLSSignature, error) {
var epoch = s.chainSpec.SlotToEpoch(slot)
signingRoot := forkData.ComputeRandaoSigningRoot(
s.chainSpec.DomainTypeRandao(),
epoch,
)
Expand Down
5 changes: 5 additions & 0 deletions beacon/validator/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ type BlobFactory[
BuildSidecars(
blk BeaconBlockT,
blobs engineprimitives.BlobsBundle,
signer crypto.BLSSigner,
forkData *ctypes.ForkData,

) (BlobSidecarsT, error)
}

Expand Down Expand Up @@ -150,6 +153,8 @@ type ForkData[T any] interface {
common.DomainType,
math.Epoch,
) common.Root
// ComputeDomain computes the fork data domain for a given domain type.
ComputeDomain(common.DomainType) common.Domain
}

// PayloadBuilder represents a service that is responsible for
Expand Down
130 changes: 130 additions & 0 deletions consensus-types/types/signed_header.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
// SPDX-License-Identifier: BUSL-1.1
//
// Copyright (C) 2024, Berachain Foundation. All rights reserved.
// Use of this software is governed by the Business Source License included
// in the LICENSE file of this repository and at www.mariadb.com/bsl11.
//
// ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY
// TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER
// VERSIONS OF THE LICENSED WORK.
//
// THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF
// LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF
// LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE).
//
// TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
// AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
// EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
// TITLE.

package types

import (
"github.com/berachain/beacon-kit/primitives/common"
"github.com/berachain/beacon-kit/primitives/constraints"
"github.com/berachain/beacon-kit/primitives/crypto"
"github.com/karalabe/ssz"
)

var (
_ ssz.StaticObject = (*SignedBeaconBlockHeader)(nil)
_ constraints.SSZMarshallableRootable = (*SignedBeaconBlockHeader)(nil)
)

type SignedBeaconBlockHeader struct {
Header *BeaconBlockHeader `json:"header"`
Signature crypto.BLSSignature `json:"signature"`
}

/* -------------------------------------------------------------------------- */
/* Constructor */
/* -------------------------------------------------------------------------- */

// NewSignedBeaconBlockHeader creates a new BeaconBlockHeader.
func NewSignedBeaconBlockHeader(
header *BeaconBlockHeader,
signature crypto.BLSSignature,
) *SignedBeaconBlockHeader {
return &SignedBeaconBlockHeader{
header, signature,
}
}

// Empty creates an empty BeaconBlockHeader instance.
func (*SignedBeaconBlockHeader) Empty() *SignedBeaconBlockHeader {
return &SignedBeaconBlockHeader{}
}

// New creates a new SignedBeaconBlockHeader.
func (b *SignedBeaconBlockHeader) New(
header *BeaconBlockHeader,
signature crypto.BLSSignature,
) *SignedBeaconBlockHeader {
return NewSignedBeaconBlockHeader(
header, signature,
)
}

/* -------------------------------------------------------------------------- */
/* SSZ */
/* -------------------------------------------------------------------------- */

// SizeSSZ returns the size of the SignedBeaconBlockHeader object
// in SSZ encoding. Total size: Header (112) + Signature (96).
func (b *SignedBeaconBlockHeader) SizeSSZ(sizer *ssz.Sizer) uint32 {
//nolint:mnd // no magic
size := (*BeaconBlockHeader)(nil).SizeSSZ(sizer) + 96
return size
}

// DefineSSZ defines the SSZ encoding for the SignedBeaconBlockHeader object.
func (b *SignedBeaconBlockHeader) DefineSSZ(codec *ssz.Codec) {
ssz.DefineStaticObject(codec, &b.Header)
ssz.DefineStaticBytes(codec, &b.Signature)
}

// MarshalSSZ marshals the SignedBeaconBlockHeader object to SSZ format.
func (b *SignedBeaconBlockHeader) MarshalSSZ() ([]byte, error) {
buf := make([]byte, ssz.Size(b))
return buf, ssz.EncodeToBytes(buf, b)
}

// UnmarshalSSZ unmarshals the SignedBeaconBlockHeader object from SSZ format.
func (b *SignedBeaconBlockHeader) UnmarshalSSZ(buf []byte) error {
return ssz.DecodeFromBytes(buf, b)
}

// HashTreeRoot computes the SSZ hash tree root of the
// SignedBeaconBlockHeader object.
func (b *SignedBeaconBlockHeader) HashTreeRoot() common.Root {
return ssz.HashSequential(b)
}

/* -------------------------------------------------------------------------- */
/* Getters and Setters */
/* -------------------------------------------------------------------------- */

// Getheader retrieves the header of the SignedBeaconBlockHeader.
func (b *SignedBeaconBlockHeader) GetHeader() *BeaconBlockHeader {
return b.Header
}

// Setheader sets the header of the BeaconBlockHeader.
func (b *SignedBeaconBlockHeader) SetHeader(header *BeaconBlockHeader) {
b.Header = header
}

// GetSignature retrieves the Signature of the SignedBeaconBlockHeader.
func (b *SignedBeaconBlockHeader) GetSignature() crypto.BLSSignature {
return b.Signature
}

// SetSignature sets the Signature of the BeaconBlockHeader.
func (b *SignedBeaconBlockHeader) SetSignature(signature crypto.BLSSignature) {
b.Signature = signature
}

func (b *SignedBeaconBlockHeader) IsNil() bool {
return b == nil
}
Loading

0 comments on commit 5246cf5

Please sign in to comment.