Compare commits

...

17 Commits

Author SHA1 Message Date
kasey
3fa6d3bd9d update to latest version of our fastssz fork (#14519)
Co-authored-by: Kasey Kirkham <kasey@users.noreply.github.com>
2024-10-08 19:24:50 +00:00
Rupam Dey
56f0eb1437 feat: add Electra support to light client functions (#14506)
* add Electra to switch case in light client functions

* replace `!=` with `<` in `blockToLightClientHeaderXXX`

* add Electra tests

* update `CHANGELOG.md`

* add constant for Electra

* add constant to `minimal.go`

---------

Co-authored-by: Radosław Kapka <rkapka@wp.pl>
2024-10-08 18:13:13 +00:00
Bastin
7fc5c714a1 Light Client consensus types (#14518)
* protos/SSZ

* interfaces

* types

* cleanup/dedup

* changelog

* use createBranch in headers

* error handling

---------

Co-authored-by: rkapka <radoslaw.kapka@gmail.com>
2024-10-08 17:07:56 +00:00
james-prysm
cfbfccb203 Fix: validator status cache does not clear upon key removal (#14504)
* adding fix and unit test

* Update validator.go

Co-authored-by: Preston Van Loon <pvanloon@offchainlabs.com>

* fixing linting

---------

Co-authored-by: Preston Van Loon <pvanloon@offchainlabs.com>
2024-10-07 14:35:10 +00:00
Potuz
884b663455 Move back ConvertKzgCommitmentToVersionedHash to primitives package (#14508)
* Move back ConvertKzgCommitmentToVersionedHash to primitives package

* Changelog
2024-10-07 14:33:23 +00:00
Radosław Kapka
0f1d16c599 Flip committee aware packing flag (#14507)
* Flip committee aware packing flag

* changelog

* fix deprecated flag name

* test fixes

* properly use feature in tests

* Update beacon-chain/rpc/prysm/v1alpha1/validator/proposer_attestations_test.go

Co-authored-by: Sammy Rosso <15244892+saolyn@users.noreply.github.com>

---------

Co-authored-by: Sammy Rosso <15244892+saolyn@users.noreply.github.com>
2024-10-07 13:36:10 +00:00
kasey
c11e3392d4 SSE implementation that sheds stuck clients (#14413)
* sse implementation that sheds stuck clients

* Radek and James feedback

* Refactor event streamer code for readability

* less-flaky test signaling

* test case where queue fills; fixes

* add changelog entry

* james and preston feedback

* swap our Subscription interface with an alias

* event.Data can be nil for the payload attr event

* deepsource

---------

Co-authored-by: Kasey Kirkham <kasey@users.noreply.github.com>
2024-10-04 21:18:17 +00:00
Radosław Kapka
f498463843 Register deposit snapshot endpoint (#14503) 2024-10-04 16:42:30 +00:00
Radosław Kapka
cf4ffc97e2 Update block Beacon APIs to Electra (#14488)
* Update block Beacon APIs to Electra

* CHANGELOG

* Revert "Auxiliary commit to revert individual files from 9bf238279a696dbcd65440606b0e3173f3be5e05"

This reverts commit a7ef57a2532f9ee02831d180926f7b84f5104a2b.

* review

---------

Co-authored-by: james-prysm <90280386+james-prysm@users.noreply.github.com>
2024-10-04 08:21:08 +00:00
Bastin
3824e8a463 Make block_to_lightclient_header_XXX functions private (#14502)
* make block to lightclient header functions private

* changelog

* fix `helpers.go`

---------

Co-authored-by: Rupam Dey <117000803+rupam-04@users.noreply.github.com>
Co-authored-by: rupam-04 <rpmdey2004@gmail.com>
2024-10-03 21:59:07 +00:00
Rupam Dey
21ca4e008f Update lc functions to use the dev branch of CL specs (#14471)
* create finalized header based on finalized block version

* changelog entry

* pass attested block from handlers

* fix core tests

* add test for attested header exectution fields

* changelog entry

* remove unused functions

* update `createLightClientBootstrapXXX` functions

* fix for getBootstrapAltair

* fix for getBootstrapAltair

* fix tests for Capella and Deneb

* update `CHANGELOG.md`

* remove Electra from `createLightClientBootstrap` switch case

* update dependencies

* minor fixes

* remove unnecessary comments

* replace `!reflect.DeepEqual` with `!=`

* replace `%s` with `%#x` for `[32]byte`

---------

Co-authored-by: Inspector-Butters <mohamadbastin@gmail.com>
Co-authored-by: Bastin <43618253+Inspector-Butters@users.noreply.github.com>
2024-10-03 20:52:21 +00:00
Bastin
6af44a1466 Fix lc execution header bug (#14468)
* create finalized header based on finalized block version

* changelog entry

* pass attested block from handlers

* fix core tests

* add test for attested header exectution fields

* changelog entry

* remove unused functions

* Update beacon-chain/core/light-client/lightclient.go

Co-authored-by: Radosław Kapka <radoslaw.kapka@gmail.com>

* Update beacon-chain/core/light-client/lightclient.go

Co-authored-by: Radosław Kapka <radoslaw.kapka@gmail.com>

* Update beacon-chain/core/light-client/lightclient.go

Co-authored-by: Radosław Kapka <radoslaw.kapka@gmail.com>

* remove finalized header from default update

* remove unused functions

* bazel deps

---------

Co-authored-by: Radosław Kapka <radoslaw.kapka@gmail.com>
2024-10-03 17:29:22 +00:00
Owen
2e29164582 allow users to publish blobs (#14442)
* allow users to publish blobs

Allowing users to publish blobs before publishing blocks, gives the blobs a head start. They can begin to propagate around the network while the block is being validated.

* Update beacon-chain/rpc/prysm/beacon/handlers.go

* Update beacon-chain/rpc/prysm/beacon/handlers.go

* Update beacon-chain/rpc/prysm/beacon/handlers.go

* Update beacon-chain/rpc/prysm/beacon/handlers.go

* Update beacon-chain/rpc/prysm/beacon/handlers.go

* Update beacon-chain/rpc/prysm/beacon/handlers.go

* Update beacon-chain/rpc/prysm/beacon/handlers.go

* Update beacon-chain/rpc/prysm/beacon/handlers.go

* Update beacon-chain/rpc/prysm/beacon/handlers.go

* Update beacon-chain/rpc/prysm/beacon/handlers.go

---------

Co-authored-by: Radosław Kapka <radoslaw.kapka@gmail.com>
2024-10-01 20:13:41 +00:00
Ferran Borreguero
6d499bc9fc Enable electra interop genesis (#14465)
* Add Electra hard fork to interop genesis

* Update Changelog

* Fix develop merge

* gazelle

---------

Co-authored-by: james-prysm <90280386+james-prysm@users.noreply.github.com>
Co-authored-by: Preston Van Loon <pvanloon@offchainlabs.com>
2024-10-01 14:35:36 +00:00
Bastin
7786cb5684 create lc finalized header based on finalized block version (#14457)
* create finalized header based on finalized block version

* changelog entry

* refactor tests
2024-09-30 16:38:51 +00:00
terence
003b70c34b Update sepolia bootnodes (#14485)
* Add sepolia bootnodes

* Change log
2024-09-26 23:28:36 +00:00
Preston Van Loon
71edf96c7d Add sepolia config.yaml check with eth-clients/sepolia (#14484)
* Add sepolia config.yaml check with eth-clients/sepolia

* Update CHANGELOG.md
2024-09-26 13:26:12 +00:00
90 changed files with 9584 additions and 1781 deletions

View File

@@ -13,12 +13,20 @@ The format is based on Keep a Changelog, and this project adheres to Semantic Ve
- Light client support: Implement `ComputeFieldRootsForBlockBody`.
- Light client support: Add light client database changes.
- Light client support: Implement capella and deneb changes.
- Light client support: Implement `BlockToLightClientHeaderXXX` functions upto Deneb
- Light client support: Implement `BlockToLightClientHeader` function.
- Light client support: Consensus types.
- GetBeaconStateV2: add Electra case.
- Implement [consensus-specs/3875](https://github.com/ethereum/consensus-specs/pull/3875)
- Tests to ensure sepolia config matches the official upstream yaml
- HTTP endpoint for PublishBlobs
- GetBlockV2, GetBlindedBlock, ProduceBlockV2, ProduceBlockV3: add Electra case.
- Add Electra support and tests for light client functions
- fastssz version bump (better error messages).
- SSE implementation that sheds stuck clients. [pr](https://github.com/prysmaticlabs/prysm/pull/14413)
### Changed
- Electra: Updated interop genesis generator to support Electra.
- `getLocalPayload` has been refactored to enable work in ePBS branch.
- `TestNodeServer_GetPeer` and `TestNodeServer_ListPeers` test flakes resolved by iterating the whole peer list to find
a match rather than taking the first peer in the map.
@@ -39,7 +47,11 @@ The format is based on Keep a Changelog, and this project adheres to Semantic Ve
- Updated k8s-io/client-go to v0.30.4 and k8s-io/apimachinery to v0.30.4
- Migrated tracing library from opencensus to opentelemetry for both the beacon node and validator.
- Refactored light client code to make it more readable and make future PRs easier.
- Update light client helper functions to reference `dev` branch of CL specs
- Updated Libp2p Dependencies to allow prysm to use gossipsub v1.2 .
- Updated Sepolia bootnodes.
- Make committee aware packing the default by deprecating `--enable-committee-aware-packing`.
- Moved `ConvertKzgCommitmentToVersionedHash` to the `primitives` package.
### Deprecated
- `--disable-grpc-gateway` flag is deprecated due to grpc gateway removal.
@@ -64,7 +76,10 @@ The format is based on Keep a Changelog, and this project adheres to Semantic Ve
- Core: Fixed slash processing causing extra hashing.
- Core: Fixed extra allocations when processing slashings.
- remove unneeded container in blob sidecar ssz response
- Light client support: create finalized header based on finalizedBlock's version, not attestedBlock.
- Light client support: fix light client attested header execution fields' wrong version bug.
- Testing: added custom matcher for better push settings testing.
- Registered `GetDepositSnapshot` Beacon API endpoint.
### Security

View File

@@ -342,6 +342,22 @@ filegroup(
url = "https://github.com/eth-clients/holesky/archive/874c199423ccd180607320c38cbaca05d9a1573a.tar.gz", # 2024-06-18
)
http_archive(
name = "sepolia_testnet",
build_file_content = """
filegroup(
name = "configs",
srcs = [
"metadata/config.yaml",
],
visibility = ["//visibility:public"],
)
""",
integrity = "sha256-cY/UgpCcYEhQf7JefD65FI8tn/A+rAvKhcm2/qiVdqY=",
strip_prefix = "sepolia-f2c219a93c4491cee3d90c18f2f8e82aed850eab",
url = "https://github.com/eth-clients/sepolia/archive/f2c219a93c4491cee3d90c18f2f8e82aed850eab.tar.gz", # 2024-09-19
)
http_archive(
name = "com_google_protobuf",
sha256 = "9bd87b8280ef720d3240514f884e56a712f2218f0d693b48050c836028940a42",

View File

@@ -1,5 +1,7 @@
package api
import "net/http"
const (
VersionHeader = "Eth-Consensus-Version"
ExecutionPayloadBlindedHeader = "Eth-Execution-Payload-Blinded"
@@ -10,3 +12,9 @@ const (
EventStreamMediaType = "text/event-stream"
KeepAlive = "keep-alive"
)
// SetSSEHeaders sets the headers needed for a server-sent event response.
func SetSSEHeaders(w http.ResponseWriter) {
w.Header().Set("Content-Type", EventStreamMediaType)
w.Header().Set("Connection", KeepAlive)
}

View File

@@ -5,6 +5,7 @@ go_library(
srcs = [
"block.go",
"conversions.go",
"conversions_blob.go",
"conversions_block.go",
"conversions_lightclient.go",
"conversions_state.go",

View File

@@ -15,6 +15,7 @@ import (
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v5/math"
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
ethv1 "github.com/prysmaticlabs/prysm/v5/proto/eth/v1"
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
)
@@ -1508,3 +1509,37 @@ func PendingConsolidationsFromConsensus(cs []*eth.PendingConsolidation) []*Pendi
}
return consolidations
}
func HeadEventFromV1(event *ethv1.EventHead) *HeadEvent {
return &HeadEvent{
Slot: fmt.Sprintf("%d", event.Slot),
Block: hexutil.Encode(event.Block),
State: hexutil.Encode(event.State),
EpochTransition: event.EpochTransition,
ExecutionOptimistic: event.ExecutionOptimistic,
PreviousDutyDependentRoot: hexutil.Encode(event.PreviousDutyDependentRoot),
CurrentDutyDependentRoot: hexutil.Encode(event.CurrentDutyDependentRoot),
}
}
func FinalizedCheckpointEventFromV1(event *ethv1.EventFinalizedCheckpoint) *FinalizedCheckpointEvent {
return &FinalizedCheckpointEvent{
Block: hexutil.Encode(event.Block),
State: hexutil.Encode(event.State),
Epoch: fmt.Sprintf("%d", event.Epoch),
ExecutionOptimistic: event.ExecutionOptimistic,
}
}
func EventChainReorgFromV1(event *ethv1.EventChainReorg) *ChainReorgEvent {
return &ChainReorgEvent{
Slot: fmt.Sprintf("%d", event.Slot),
Depth: fmt.Sprintf("%d", event.Depth),
OldHeadBlock: hexutil.Encode(event.OldHeadBlock),
NewHeadBlock: hexutil.Encode(event.NewHeadBlock),
OldHeadState: hexutil.Encode(event.OldHeadState),
NewHeadState: hexutil.Encode(event.NewHeadState),
Epoch: fmt.Sprintf("%d", event.Epoch),
ExecutionOptimistic: event.ExecutionOptimistic,
}
}

View File

@@ -0,0 +1,61 @@
package structs
import (
"strconv"
"github.com/prysmaticlabs/prysm/v5/api/server"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
)
func (sc *Sidecar) ToConsensus() (*eth.BlobSidecar, error) {
if sc == nil {
return nil, errNilValue
}
index, err := strconv.ParseUint(sc.Index, 10, 64)
if err != nil {
return nil, server.NewDecodeError(err, "Index")
}
blob, err := bytesutil.DecodeHexWithLength(sc.Blob, 131072)
if err != nil {
return nil, server.NewDecodeError(err, "Blob")
}
kzgCommitment, err := bytesutil.DecodeHexWithLength(sc.KzgCommitment, 48)
if err != nil {
return nil, server.NewDecodeError(err, "KzgCommitment")
}
kzgProof, err := bytesutil.DecodeHexWithLength(sc.KzgProof, 48)
if err != nil {
return nil, server.NewDecodeError(err, "KzgProof")
}
header, err := sc.SignedBeaconBlockHeader.ToConsensus()
if err != nil {
return nil, server.NewDecodeError(err, "SignedBeaconBlockHeader")
}
// decode the commitment inclusion proof
var commitmentInclusionProof [][]byte
for _, proof := range sc.CommitmentInclusionProof {
proofBytes, err := bytesutil.DecodeHexWithLength(proof, 32)
if err != nil {
return nil, server.NewDecodeError(err, "CommitmentInclusionProof")
}
commitmentInclusionProof = append(commitmentInclusionProof, proofBytes)
}
bsc := &eth.BlobSidecar{
Index: index,
Blob: blob,
KzgCommitment: kzgCommitment,
KzgProof: kzgProof,
SignedBlockHeader: header,
CommitmentInclusionProof: commitmentInclusionProof,
}
return bsc, nil
}

View File

@@ -20,6 +20,9 @@ import (
var ErrUnsupportedConversion = errors.New("Could not determine api struct type to use for value")
func (h *SignedBeaconBlockHeader) ToConsensus() (*eth.SignedBeaconBlockHeader, error) {
if h == nil {
return nil, errNilValue
}
msg, err := h.Message.ToConsensus()
if err != nil {
return nil, server.NewDecodeError(err, "Message")
@@ -36,6 +39,9 @@ func (h *SignedBeaconBlockHeader) ToConsensus() (*eth.SignedBeaconBlockHeader, e
}
func (h *BeaconBlockHeader) ToConsensus() (*eth.BeaconBlockHeader, error) {
if h == nil {
return nil, errNilValue
}
s, err := strconv.ParseUint(h.Slot, 10, 64)
if err != nil {
return nil, server.NewDecodeError(err, "Slot")
@@ -2548,6 +2554,8 @@ func SignedBeaconBlockMessageJsoner(block interfaces.ReadOnlySignedBeaconBlock)
return SignedBlindedBeaconBlockDenebFromConsensus(pbStruct)
case *eth.SignedBeaconBlockDeneb:
return SignedBeaconBlockDenebFromConsensus(pbStruct)
case *eth.SignedBlindedBeaconBlockElectra:
return SignedBlindedBeaconBlockElectraFromConsensus(pbStruct)
case *eth.SignedBeaconBlockElectra:
return SignedBeaconBlockElectraFromConsensus(pbStruct)
default:

View File

@@ -84,6 +84,11 @@ func syncAggregateToJSON(input *v1.SyncAggregate) *SyncAggregate {
}
func lightClientHeaderContainerToJSON(container *v2.LightClientHeaderContainer) (json.RawMessage, error) {
// In the case that a finalizedHeader is nil.
if container == nil {
return nil, nil
}
beacon, err := container.GetBeacon()
if err != nil {
return nil, errors.Wrap(err, "could not get beacon block header")

View File

@@ -12,3 +12,12 @@ type Sidecar struct {
KzgProof string `json:"kzg_proof"`
CommitmentInclusionProof []string `json:"kzg_commitment_inclusion_proof"`
}
type BlobSidecars struct {
Sidecars []*Sidecar `json:"sidecars"`
}
type PublishBlobsRequest struct {
BlobSidecars *BlobSidecars `json:"blob_sidecars"`
BlockRoot string `json:"block_root"`
}

View File

@@ -4,6 +4,7 @@ go_library(
name = "go_default_library",
srcs = [
"feed.go",
"interface.go",
"subscription.go",
],
importpath = "github.com/prysmaticlabs/prysm/v5/async/event",

View File

@@ -22,3 +22,4 @@ import (
// Feed is a re-export of the go-ethereum event feed.
type Feed = geth_event.Feed
type Subscription = geth_event.Subscription

8
async/event/interface.go Normal file
View File

@@ -0,0 +1,8 @@
package event
// SubscriberSender is an abstract representation of an *event.Feed
// to use in describing types that accept or return an *event.Feed.
type SubscriberSender interface {
Subscribe(channel interface{}) Subscription
Send(value interface{}) (nsent int)
}

View File

@@ -28,25 +28,6 @@ import (
// request backoff time.
const waitQuotient = 10
// Subscription represents a stream of events. The carrier of the events is typically a
// channel, but isn't part of the interface.
//
// Subscriptions can fail while established. Failures are reported through an error
// channel. It receives a value if there is an issue with the subscription (e.g. the
// network connection delivering the events has been closed). Only one value will ever be
// sent.
//
// The error channel is closed when the subscription ends successfully (i.e. when the
// source of events is closed). It is also closed when Unsubscribe is called.
//
// The Unsubscribe method cancels the sending of events. You must call Unsubscribe in all
// cases to ensure that resources related to the subscription are released. It can be
// called any number of times.
type Subscription interface {
Err() <-chan error // returns the error channel
Unsubscribe() // cancels sending of events, closing the error channel
}
// NewSubscription runs a producer function as a subscription in a new goroutine. The
// channel given to the producer is closed when Unsubscribe is called. If fn returns an
// error, it is sent on the subscription's error channel.

View File

@@ -2,7 +2,6 @@ package blockchain
import (
"context"
"crypto/sha256"
"fmt"
"github.com/ethereum/go-ethereum/common"
@@ -28,8 +27,6 @@ import (
"github.com/sirupsen/logrus"
)
const blobCommitmentVersionKZG uint8 = 0x01
var defaultLatestValidHash = bytesutil.PadTo([]byte{0xff}, 32)
// notifyForkchoiceUpdate signals execution engine the fork choice updates. Execution engine should:
@@ -402,13 +399,7 @@ func kzgCommitmentsToVersionedHashes(body interfaces.ReadOnlyBeaconBlockBody) ([
versionedHashes := make([]common.Hash, len(commitments))
for i, commitment := range commitments {
versionedHashes[i] = ConvertKzgCommitmentToVersionedHash(commitment)
versionedHashes[i] = primitives.ConvertKzgCommitmentToVersionedHash(commitment)
}
return versionedHashes, nil
}
func ConvertKzgCommitmentToVersionedHash(commitment []byte) common.Hash {
versionedHash := sha256.Sum256(commitment)
versionedHash[0] = blobCommitmentVersionKZG
return versionedHash
}

View File

@@ -162,6 +162,10 @@ func (s *Service) sendLightClientFinalityUpdate(ctx context.Context, signed inte
postState state.BeaconState) (int, error) {
// Get attested state
attestedRoot := signed.Block().ParentRoot()
attestedBlock, err := s.cfg.BeaconDB.Block(ctx, attestedRoot)
if err != nil {
return 0, errors.Wrap(err, "could not get attested block")
}
attestedState, err := s.cfg.StateGen.StateByRoot(ctx, attestedRoot)
if err != nil {
return 0, errors.Wrap(err, "could not get attested state")
@@ -183,6 +187,7 @@ func (s *Service) sendLightClientFinalityUpdate(ctx context.Context, signed inte
postState,
signed,
attestedState,
attestedBlock,
finalizedBlock,
)
@@ -208,6 +213,10 @@ func (s *Service) sendLightClientOptimisticUpdate(ctx context.Context, signed in
postState state.BeaconState) (int, error) {
// Get attested state
attestedRoot := signed.Block().ParentRoot()
attestedBlock, err := s.cfg.BeaconDB.Block(ctx, attestedRoot)
if err != nil {
return 0, errors.Wrap(err, "could not get attested block")
}
attestedState, err := s.cfg.StateGen.StateByRoot(ctx, attestedRoot)
if err != nil {
return 0, errors.Wrap(err, "could not get attested state")
@@ -218,6 +227,7 @@ func (s *Service) sendLightClientOptimisticUpdate(ctx context.Context, signed in
postState,
signed,
attestedState,
attestedBlock,
)
if err != nil {

View File

@@ -32,7 +32,7 @@ type mockBeaconNode struct {
}
// StateFeed mocks the same method in the beacon node.
func (mbn *mockBeaconNode) StateFeed() *event.Feed {
func (mbn *mockBeaconNode) StateFeed() event.SubscriberSender {
mbn.mu.Lock()
defer mbn.mu.Unlock()
if mbn.stateFeed == nil {

View File

@@ -98,6 +98,44 @@ func (s *ChainService) BlockNotifier() blockfeed.Notifier {
return s.blockNotifier
}
type EventFeedWrapper struct {
feed *event.Feed
subscribed chan struct{} // this channel is closed once a subscription is made
}
func (w *EventFeedWrapper) Subscribe(channel interface{}) event.Subscription {
select {
case <-w.subscribed:
break // already closed
default:
close(w.subscribed)
}
return w.feed.Subscribe(channel)
}
func (w *EventFeedWrapper) Send(value interface{}) int {
return w.feed.Send(value)
}
// WaitForSubscription allows test to wait for the feed to have a subscription before beginning to send events.
func (w *EventFeedWrapper) WaitForSubscription(ctx context.Context) error {
select {
case <-w.subscribed:
return nil
case <-ctx.Done():
return ctx.Err()
}
}
var _ event.SubscriberSender = &EventFeedWrapper{}
func NewEventFeedWrapper() *EventFeedWrapper {
return &EventFeedWrapper{
feed: new(event.Feed),
subscribed: make(chan struct{}),
}
}
// MockBlockNotifier mocks the block notifier.
type MockBlockNotifier struct {
feed *event.Feed
@@ -131,7 +169,7 @@ func (msn *MockStateNotifier) ReceivedEvents() []*feed.Event {
}
// StateFeed returns a state feed.
func (msn *MockStateNotifier) StateFeed() *event.Feed {
func (msn *MockStateNotifier) StateFeed() event.SubscriberSender {
msn.feedLock.Lock()
defer msn.feedLock.Unlock()
@@ -159,6 +197,23 @@ func (msn *MockStateNotifier) StateFeed() *event.Feed {
return msn.feed
}
// NewSimpleStateNotifier makes a state feed without the custom mock feed machinery.
func NewSimpleStateNotifier() *MockStateNotifier {
return &MockStateNotifier{feed: new(event.Feed)}
}
type SimpleNotifier struct {
Feed event.SubscriberSender
}
func (n *SimpleNotifier) StateFeed() event.SubscriberSender {
return n.Feed
}
func (n *SimpleNotifier) OperationFeed() event.SubscriberSender {
return n.Feed
}
// OperationNotifier mocks the same method in the chain service.
func (s *ChainService) OperationNotifier() opfeed.Notifier {
if s.opNotifier == nil {
@@ -173,7 +228,7 @@ type MockOperationNotifier struct {
}
// OperationFeed returns an operation feed.
func (mon *MockOperationNotifier) OperationFeed() *event.Feed {
func (mon *MockOperationNotifier) OperationFeed() event.SubscriberSender {
if mon.feed == nil {
mon.feed = new(event.Feed)
}

View File

@@ -4,5 +4,5 @@ import "github.com/prysmaticlabs/prysm/v5/async/event"
// Notifier interface defines the methods of the service that provides beacon block operation updates to consumers.
type Notifier interface {
OperationFeed() *event.Feed
OperationFeed() event.SubscriberSender
}

View File

@@ -4,5 +4,5 @@ import "github.com/prysmaticlabs/prysm/v5/async/event"
// Notifier interface defines the methods of the service that provides state updates to consumers.
type Notifier interface {
StateFeed() *event.Feed
StateFeed() event.SubscriberSender
}

View File

@@ -12,12 +12,10 @@ go_library(
"//consensus-types:go_default_library",
"//consensus-types/blocks:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//encoding/bytesutil:go_default_library",
"//encoding/ssz:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/eth/v1:go_default_library",
"//proto/eth/v2:go_default_library",
"//proto/migration:go_default_library",
"//runtime/version:go_default_library",
"//time/slots:go_default_library",
"@com_github_pkg_errors//:go_default_library",
@@ -29,11 +27,13 @@ go_test(
srcs = ["lightclient_test.go"],
deps = [
":go_default_library",
"//config/params:go_default_library",
"//config/fieldparams:go_default_library",
"//consensus-types:go_default_library",
"//consensus-types/blocks:go_default_library",
"//consensus-types/primitives:go_default_library",
"//encoding/ssz:go_default_library",
"//proto/engine/v1:go_default_library",
"//testing/require:go_default_library",
"//testing/util:go_default_library",
"@com_github_pkg_errors//:go_default_library",
],
)

View File

@@ -13,15 +13,11 @@ import (
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/v5/encoding/ssz"
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
v11 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
ethpbv1 "github.com/prysmaticlabs/prysm/v5/proto/eth/v1"
ethpbv2 "github.com/prysmaticlabs/prysm/v5/proto/eth/v2"
"github.com/prysmaticlabs/prysm/v5/proto/migration"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/prysmaticlabs/prysm/v5/time/slots"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
)
const (
@@ -29,16 +25,6 @@ const (
executionBranchNumOfLeaves = 4
)
// createLightClientFinalityUpdate - implements https://github.com/ethereum/consensus-specs/blob/3d235740e5f1e641d3b160c8688f26e7dc5a1894/specs/altair/light-client/full-node.md#create_light_client_finality_update
// def create_light_client_finality_update(update: LightClientUpdate) -> LightClientFinalityUpdate:
//
// return LightClientFinalityUpdate(
// attested_header=update.attested_header,
// finalized_header=update.finalized_header,
// finality_branch=update.finality_branch,
// sync_aggregate=update.sync_aggregate,
// signature_slot=update.signature_slot,
// )
func createLightClientFinalityUpdate(update *ethpbv2.LightClientUpdate) *ethpbv2.LightClientFinalityUpdate {
finalityUpdate := &ethpbv2.LightClientFinalityUpdate{
AttestedHeader: update.AttestedHeader,
@@ -51,14 +37,6 @@ func createLightClientFinalityUpdate(update *ethpbv2.LightClientUpdate) *ethpbv2
return finalityUpdate
}
// createLightClientOptimisticUpdate - implements https://github.com/ethereum/consensus-specs/blob/3d235740e5f1e641d3b160c8688f26e7dc5a1894/specs/altair/light-client/full-node.md#create_light_client_optimistic_update
// def create_light_client_optimistic_update(update: LightClientUpdate) -> LightClientOptimisticUpdate:
//
// return LightClientOptimisticUpdate(
// attested_header=update.attested_header,
// sync_aggregate=update.sync_aggregate,
// signature_slot=update.signature_slot,
// )
func createLightClientOptimisticUpdate(update *ethpbv2.LightClientUpdate) *ethpbv2.LightClientOptimisticUpdate {
optimisticUpdate := &ethpbv2.LightClientOptimisticUpdate{
AttestedHeader: update.AttestedHeader,
@@ -74,9 +52,10 @@ func NewLightClientFinalityUpdateFromBeaconState(
state state.BeaconState,
block interfaces.ReadOnlySignedBeaconBlock,
attestedState state.BeaconState,
attestedBlock interfaces.ReadOnlySignedBeaconBlock,
finalizedBlock interfaces.ReadOnlySignedBeaconBlock,
) (*ethpbv2.LightClientFinalityUpdate, error) {
update, err := NewLightClientUpdateFromBeaconState(ctx, state, block, attestedState, finalizedBlock)
update, err := NewLightClientUpdateFromBeaconState(ctx, state, block, attestedState, attestedBlock, finalizedBlock)
if err != nil {
return nil, err
}
@@ -89,8 +68,9 @@ func NewLightClientOptimisticUpdateFromBeaconState(
state state.BeaconState,
block interfaces.ReadOnlySignedBeaconBlock,
attestedState state.BeaconState,
attestedBlock interfaces.ReadOnlySignedBeaconBlock,
) (*ethpbv2.LightClientOptimisticUpdate, error) {
update, err := NewLightClientUpdateFromBeaconState(ctx, state, block, attestedState, nil)
update, err := NewLightClientUpdateFromBeaconState(ctx, state, block, attestedState, attestedBlock, nil)
if err != nil {
return nil, err
}
@@ -98,68 +78,12 @@ func NewLightClientOptimisticUpdateFromBeaconState(
return createLightClientOptimisticUpdate(update), nil
}
// NewLightClientUpdateFromBeaconState implements https://github.com/ethereum/consensus-specs/blob/d70dcd9926a4bbe987f1b4e65c3e05bd029fcfb8/specs/altair/light-client/full-node.md#create_light_client_update
// def create_light_client_update(state: BeaconState,
//
// block: SignedBeaconBlock,
// attested_state: BeaconState,
// finalized_block: Optional[SignedBeaconBlock]) -> LightClientUpdate:
// assert compute_epoch_at_slot(attested_state.slot) >= ALTAIR_FORK_EPOCH
// assert sum(block.message.body.sync_aggregate.sync_committee_bits) >= MIN_SYNC_COMMITTEE_PARTICIPANTS
//
// assert state.slot == state.latest_block_header.slot
// header = state.latest_block_header.copy()
// header.state_root = hash_tree_root(state)
// assert hash_tree_root(header) == hash_tree_root(block.message)
// update_signature_period = compute_sync_committee_period(compute_epoch_at_slot(block.message.slot))
//
// assert attested_state.slot == attested_state.latest_block_header.slot
// attested_header = attested_state.latest_block_header.copy()
// attested_header.state_root = hash_tree_root(attested_state)
// assert hash_tree_root(attested_header) == block.message.parent_root
// update_attested_period = compute_sync_committee_period(compute_epoch_at_slot(attested_header.slot))
//
// # `next_sync_committee` is only useful if the message is signed by the current sync committee
// if update_attested_period == update_signature_period:
// next_sync_committee = attested_state.next_sync_committee
// next_sync_committee_branch = compute_merkle_proof_for_state(attested_state, NEXT_SYNC_COMMITTEE_INDEX)
// else:
// next_sync_committee = SyncCommittee()
// next_sync_committee_branch = [Bytes32() for _ in range(floorlog2(NEXT_SYNC_COMMITTEE_INDEX))]
//
// # Indicate finality whenever possible
// if finalized_block is not None:
// if finalized_block.message.slot != GENESIS_SLOT:
// finalized_header = BeaconBlockHeader(
// slot=finalized_block.message.slot,
// proposer_index=finalized_block.message.proposer_index,
// parent_root=finalized_block.message.parent_root,
// state_root=finalized_block.message.state_root,
// body_root=hash_tree_root(finalized_block.message.body),
// )
// assert hash_tree_root(finalized_header) == attested_state.finalized_checkpoint.root
// else:
// assert attested_state.finalized_checkpoint.root == Bytes32()
// finalized_header = BeaconBlockHeader()
// finality_branch = compute_merkle_proof_for_state(attested_state, FINALIZED_ROOT_INDEX)
// else:
// finalized_header = BeaconBlockHeader()
// finality_branch = [Bytes32() for _ in range(floorlog2(FINALIZED_ROOT_INDEX))]
//
// return LightClientUpdate(
// attested_header=attested_header,
// next_sync_committee=next_sync_committee,
// next_sync_committee_branch=next_sync_committee_branch,
// finalized_header=finalized_header,
// finality_branch=finality_branch,
// sync_aggregate=block.message.body.sync_aggregate,
// signature_slot=block.message.slot,
// )
func NewLightClientUpdateFromBeaconState(
ctx context.Context,
state state.BeaconState,
block interfaces.ReadOnlySignedBeaconBlock,
attestedState state.BeaconState,
attestedBlock interfaces.ReadOnlySignedBeaconBlock,
finalizedBlock interfaces.ReadOnlySignedBeaconBlock) (*ethpbv2.LightClientUpdate, error) {
// assert compute_epoch_at_slot(attested_state.slot) >= ALTAIR_FORK_EPOCH
attestedEpoch := slots.ToEpoch(attestedState.Slot())
@@ -223,73 +147,30 @@ func NewLightClientUpdateFromBeaconState(
if err != nil {
return nil, errors.Wrap(err, "could not get attested header root")
}
if attestedHeaderRoot != block.Block().ParentRoot() {
return nil, fmt.Errorf("attested header root %#x not equal to block parent root %#x", attestedHeaderRoot, block.Block().ParentRoot())
attestedBlockRoot, err := attestedBlock.Block().HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "could not get attested block root")
}
// assert hash_tree_root(attested_header) == hash_tree_root(attested_block.message) == block.message.parent_root
if attestedHeaderRoot != block.Block().ParentRoot() || attestedHeaderRoot != attestedBlockRoot {
return nil, fmt.Errorf("attested header root %#x not equal to block parent root %#x or attested block root %#x", attestedHeaderRoot, block.Block().ParentRoot(), attestedBlockRoot)
}
// update_attested_period = compute_sync_committee_period(compute_epoch_at_slot(attested_header.slot))
updateAttestedPeriod := slots.SyncCommitteePeriod(slots.ToEpoch(attestedHeader.Slot))
// update_attested_period = compute_sync_committee_period_at_slot(attested_block.message.slot)
updateAttestedPeriod := slots.SyncCommitteePeriod(slots.ToEpoch(attestedBlock.Block().Slot()))
// update = LightClientUpdate()
result, err := createDefaultLightClientUpdate(block.Block().Version())
result, err := createDefaultLightClientUpdate()
if err != nil {
return nil, errors.Wrap(err, "could not create default light client update")
}
// update.attested_header = block_to_light_client_header(attested_block)
blockHeader := &ethpbv1.BeaconBlockHeader{
Slot: attestedHeader.Slot,
ProposerIndex: attestedHeader.ProposerIndex,
ParentRoot: attestedHeader.ParentRoot,
StateRoot: attestedHeader.StateRoot,
BodyRoot: attestedHeader.BodyRoot,
}
switch block.Block().Version() {
case version.Altair, version.Bellatrix:
result.AttestedHeader = &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderAltair{
HeaderAltair: &ethpbv2.LightClientHeader{Beacon: blockHeader},
},
}
case version.Capella:
executionPayloadHeader, err := getExecutionPayloadHeaderCapella(block)
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload header")
}
executionPayloadProof, err := blocks.PayloadProof(ctx, block.Block())
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload proof")
}
result.AttestedHeader = &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderCapella{
HeaderCapella: &ethpbv2.LightClientHeaderCapella{
Beacon: blockHeader,
Execution: executionPayloadHeader,
ExecutionBranch: executionPayloadProof,
},
},
}
case version.Deneb:
executionPayloadHeader, err := getExecutionPayloadHeaderDeneb(block)
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload header")
}
executionPayloadProof, err := blocks.PayloadProof(ctx, block.Block())
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload proof")
}
result.AttestedHeader = &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderDeneb{
HeaderDeneb: &ethpbv2.LightClientHeaderDeneb{
Beacon: blockHeader,
Execution: executionPayloadHeader,
ExecutionBranch: executionPayloadProof,
},
},
}
default:
return nil, fmt.Errorf("unsupported block version %s", version.String(block.Block().Version()))
attestedLightClientHeader, err := BlockToLightClientHeader(attestedBlock)
if err != nil {
return nil, errors.Wrap(err, "could not get attested light client header")
}
result.AttestedHeader = attestedLightClientHeader
// if update_attested_period == update_signature_period
if updateAttestedPeriod == updateSignaturePeriod {
@@ -319,70 +200,11 @@ func NewLightClientUpdateFromBeaconState(
// if finalized_block.message.slot != GENESIS_SLOT
if finalizedBlock.Block().Slot() != 0 {
// update.finalized_header = block_to_light_client_header(finalized_block)
v1alpha1FinalizedHeader, err := finalizedBlock.Header()
finalizedLightClientHeader, err := BlockToLightClientHeader(finalizedBlock)
if err != nil {
return nil, errors.Wrap(err, "could not get finalized header")
}
finalizedHeader := migration.V1Alpha1SignedHeaderToV1(v1alpha1FinalizedHeader).GetMessage()
finalizedHeaderRoot, err := finalizedHeader.HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "could not get finalized header root")
}
switch block.Block().Version() {
case version.Altair, version.Bellatrix:
result.FinalizedHeader = &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderAltair{
HeaderAltair: &ethpbv2.LightClientHeader{Beacon: finalizedHeader},
},
}
case version.Capella:
executionPayloadHeader, err := getExecutionPayloadHeaderCapella(finalizedBlock)
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload header")
}
executionPayloadProof, err := blocks.PayloadProof(ctx, finalizedBlock.Block())
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload proof")
}
result.FinalizedHeader = &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderCapella{
HeaderCapella: &ethpbv2.LightClientHeaderCapella{
Beacon: finalizedHeader,
Execution: executionPayloadHeader,
ExecutionBranch: executionPayloadProof,
},
},
}
case version.Deneb:
executionPayloadHeader, err := getExecutionPayloadHeaderDeneb(finalizedBlock)
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload header")
}
executionPayloadProof, err := blocks.PayloadProof(ctx, finalizedBlock.Block())
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload proof")
}
result.FinalizedHeader = &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderDeneb{
HeaderDeneb: &ethpbv2.LightClientHeaderDeneb{
Beacon: finalizedHeader,
Execution: executionPayloadHeader,
ExecutionBranch: executionPayloadProof,
},
},
}
default:
return nil, fmt.Errorf("unsupported block version %s", version.String(block.Block().Version()))
}
// assert hash_tree_root(update.finalized_header.beacon) == attested_state.finalized_checkpoint.root
if finalizedHeaderRoot != bytesutil.ToBytes32(attestedState.FinalizedCheckpoint().Root) {
return nil, fmt.Errorf(
"finalized header root %#x not equal to attested finalized checkpoint root %#x",
finalizedHeaderRoot,
bytesutil.ToBytes32(attestedState.FinalizedCheckpoint().Root),
)
return nil, errors.Wrap(err, "could not get finalized light client header")
}
result.FinalizedHeader = finalizedLightClientHeader
} else {
// assert attested_state.finalized_checkpoint.root == Bytes32()
if !bytes.Equal(attestedState.FinalizedCheckpoint().Root, make([]byte, 32)) {
@@ -411,7 +233,7 @@ func NewLightClientUpdateFromBeaconState(
return result, nil
}
func createDefaultLightClientUpdate(v int) (*ethpbv2.LightClientUpdate, error) {
func createDefaultLightClientUpdate() (*ethpbv2.LightClientUpdate, error) {
syncCommitteeSize := params.BeaconConfig().SyncCommitteeSize
pubKeys := make([][]byte, syncCommitteeSize)
for i := uint64(0); i < syncCommitteeSize; i++ {
@@ -421,218 +243,26 @@ func createDefaultLightClientUpdate(v int) (*ethpbv2.LightClientUpdate, error) {
Pubkeys: pubKeys,
AggregatePubkey: make([]byte, fieldparams.BLSPubkeyLength),
}
nextSyncCommitteeBranch := make([][]byte, fieldparams.NextSyncCommitteeBranchDepth)
for i := 0; i < fieldparams.NextSyncCommitteeBranchDepth; i++ {
nextSyncCommitteeBranch := make([][]byte, fieldparams.SyncCommitteeBranchDepth)
for i := 0; i < fieldparams.SyncCommitteeBranchDepth; i++ {
nextSyncCommitteeBranch[i] = make([]byte, fieldparams.RootLength)
}
executionBranch := make([][]byte, executionBranchNumOfLeaves)
for i := 0; i < executionBranchNumOfLeaves; i++ {
executionBranch[i] = make([]byte, 32)
}
finalizedBlockHeader := &ethpbv1.BeaconBlockHeader{
Slot: 0,
ProposerIndex: 0,
ParentRoot: make([]byte, 32),
StateRoot: make([]byte, 32),
BodyRoot: make([]byte, 32),
}
finalityBranch := make([][]byte, FinalityBranchNumOfLeaves)
for i := 0; i < FinalityBranchNumOfLeaves; i++ {
finalityBranch[i] = make([]byte, 32)
}
var finalizedHeader *ethpbv2.LightClientHeaderContainer
switch v {
case version.Altair, version.Bellatrix:
finalizedHeader = &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderAltair{
HeaderAltair: &ethpbv2.LightClientHeader{
Beacon: finalizedBlockHeader,
},
},
}
case version.Capella:
finalizedHeader = &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderCapella{
HeaderCapella: &ethpbv2.LightClientHeaderCapella{
Beacon: finalizedBlockHeader,
Execution: createEmptyExecutionPayloadHeaderCapella(),
ExecutionBranch: executionBranch,
},
},
}
case version.Deneb:
finalizedHeader = &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderDeneb{
HeaderDeneb: &ethpbv2.LightClientHeaderDeneb{
Beacon: finalizedBlockHeader,
Execution: createEmptyExecutionPayloadHeaderDeneb(),
ExecutionBranch: executionBranch,
},
},
}
default:
return nil, fmt.Errorf("unsupported block version %s", version.String(v))
}
return &ethpbv2.LightClientUpdate{
NextSyncCommittee: nextSyncCommittee,
NextSyncCommitteeBranch: nextSyncCommitteeBranch,
FinalizedHeader: finalizedHeader,
FinalityBranch: finalityBranch,
}, nil
}
func createEmptyExecutionPayloadHeaderCapella() *enginev1.ExecutionPayloadHeaderCapella {
return &enginev1.ExecutionPayloadHeaderCapella{
ParentHash: make([]byte, 32),
FeeRecipient: make([]byte, 20),
StateRoot: make([]byte, 32),
ReceiptsRoot: make([]byte, 32),
LogsBloom: make([]byte, 256),
PrevRandao: make([]byte, 32),
BlockNumber: 0,
GasLimit: 0,
GasUsed: 0,
Timestamp: 0,
ExtraData: make([]byte, 32),
BaseFeePerGas: make([]byte, 32),
BlockHash: make([]byte, 32),
TransactionsRoot: make([]byte, 32),
WithdrawalsRoot: make([]byte, 32),
}
}
func createEmptyExecutionPayloadHeaderDeneb() *enginev1.ExecutionPayloadHeaderDeneb {
return &enginev1.ExecutionPayloadHeaderDeneb{
ParentHash: make([]byte, 32),
FeeRecipient: make([]byte, 20),
StateRoot: make([]byte, 32),
ReceiptsRoot: make([]byte, 32),
LogsBloom: make([]byte, 256),
PrevRandao: make([]byte, 32),
BlockNumber: 0,
GasLimit: 0,
GasUsed: 0,
Timestamp: 0,
ExtraData: make([]byte, 32),
BaseFeePerGas: make([]byte, 32),
BlockHash: make([]byte, 32),
TransactionsRoot: make([]byte, 32),
WithdrawalsRoot: make([]byte, 32),
}
}
func getExecutionPayloadHeaderCapella(block interfaces.ReadOnlySignedBeaconBlock) (*enginev1.ExecutionPayloadHeaderCapella, error) {
payloadInterface, err := block.Block().Body().Execution()
if err != nil {
return nil, errors.Wrap(err, "could not get execution data")
}
transactionsRoot, err := payloadInterface.TransactionsRoot()
if errors.Is(err, consensus_types.ErrUnsupportedField) {
transactions, err := payloadInterface.Transactions()
if err != nil {
return nil, errors.Wrap(err, "could not get transactions")
}
transactionsRootArray, err := ssz.TransactionsRoot(transactions)
if err != nil {
return nil, errors.Wrap(err, "could not get transactions root")
}
transactionsRoot = transactionsRootArray[:]
} else if err != nil {
return nil, errors.Wrap(err, "could not get transactions root")
}
withdrawalsRoot, err := payloadInterface.WithdrawalsRoot()
if errors.Is(err, consensus_types.ErrUnsupportedField) {
withdrawals, err := payloadInterface.Withdrawals()
if err != nil {
return nil, errors.Wrap(err, "could not get withdrawals")
}
withdrawalsRootArray, err := ssz.WithdrawalSliceRoot(withdrawals, fieldparams.MaxWithdrawalsPerPayload)
if err != nil {
return nil, errors.Wrap(err, "could not get withdrawals root")
}
withdrawalsRoot = withdrawalsRootArray[:]
} else if err != nil {
return nil, errors.Wrap(err, "could not get withdrawals root")
}
execution := &enginev1.ExecutionPayloadHeaderCapella{
ParentHash: payloadInterface.ParentHash(),
FeeRecipient: payloadInterface.FeeRecipient(),
StateRoot: payloadInterface.StateRoot(),
ReceiptsRoot: payloadInterface.ReceiptsRoot(),
LogsBloom: payloadInterface.LogsBloom(),
PrevRandao: payloadInterface.PrevRandao(),
BlockNumber: payloadInterface.BlockNumber(),
GasLimit: payloadInterface.GasLimit(),
GasUsed: payloadInterface.GasUsed(),
Timestamp: payloadInterface.Timestamp(),
ExtraData: payloadInterface.ExtraData(),
BaseFeePerGas: payloadInterface.BaseFeePerGas(),
BlockHash: payloadInterface.BlockHash(),
TransactionsRoot: transactionsRoot,
WithdrawalsRoot: withdrawalsRoot,
}
return execution, nil
}
func getExecutionPayloadHeaderDeneb(block interfaces.ReadOnlySignedBeaconBlock) (*enginev1.ExecutionPayloadHeaderDeneb, error) {
payloadInterface, err := block.Block().Body().Execution()
if err != nil {
return nil, errors.Wrap(err, "could not get execution data")
}
transactionsRoot, err := payloadInterface.TransactionsRoot()
if errors.Is(err, consensus_types.ErrUnsupportedField) {
transactions, err := payloadInterface.Transactions()
if err != nil {
return nil, errors.Wrap(err, "could not get transactions")
}
transactionsRootArray, err := ssz.TransactionsRoot(transactions)
if err != nil {
return nil, errors.Wrap(err, "could not get transactions root")
}
transactionsRoot = transactionsRootArray[:]
} else if err != nil {
return nil, errors.Wrap(err, "could not get transactions root")
}
withdrawalsRoot, err := payloadInterface.WithdrawalsRoot()
if errors.Is(err, consensus_types.ErrUnsupportedField) {
withdrawals, err := payloadInterface.Withdrawals()
if err != nil {
return nil, errors.Wrap(err, "could not get withdrawals")
}
withdrawalsRootArray, err := ssz.WithdrawalSliceRoot(withdrawals, fieldparams.MaxWithdrawalsPerPayload)
if err != nil {
return nil, errors.Wrap(err, "could not get withdrawals root")
}
withdrawalsRoot = withdrawalsRootArray[:]
} else if err != nil {
return nil, errors.Wrap(err, "could not get withdrawals root")
}
execution := &enginev1.ExecutionPayloadHeaderDeneb{
ParentHash: payloadInterface.ParentHash(),
FeeRecipient: payloadInterface.FeeRecipient(),
StateRoot: payloadInterface.StateRoot(),
ReceiptsRoot: payloadInterface.ReceiptsRoot(),
LogsBloom: payloadInterface.LogsBloom(),
PrevRandao: payloadInterface.PrevRandao(),
BlockNumber: payloadInterface.BlockNumber(),
GasLimit: payloadInterface.GasLimit(),
GasUsed: payloadInterface.GasUsed(),
Timestamp: payloadInterface.Timestamp(),
ExtraData: payloadInterface.ExtraData(),
BaseFeePerGas: payloadInterface.BaseFeePerGas(),
BlockHash: payloadInterface.BlockHash(),
TransactionsRoot: transactionsRoot,
WithdrawalsRoot: withdrawalsRoot,
}
return execution, nil
}
func ComputeTransactionsRoot(payload interfaces.ExecutionData) ([]byte, error) {
transactionsRoot, err := payload.TransactionsRoot()
if errors.Is(err, consensus_types.ErrUnsupportedField) {
@@ -669,8 +299,45 @@ func ComputeWithdrawalsRoot(payload interfaces.ExecutionData) ([]byte, error) {
return withdrawalsRoot, nil
}
func BlockToLightClientHeaderAltair(block interfaces.ReadOnlySignedBeaconBlock) (*ethpbv2.LightClientHeader, error) {
if block.Version() != version.Altair {
func BlockToLightClientHeader(block interfaces.ReadOnlySignedBeaconBlock) (*ethpbv2.LightClientHeaderContainer, error) {
switch block.Version() {
case version.Altair, version.Bellatrix:
altairHeader, err := blockToLightClientHeaderAltair(block)
if err != nil {
return nil, errors.Wrap(err, "could not get header")
}
return &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderAltair{
HeaderAltair: altairHeader,
},
}, nil
case version.Capella:
capellaHeader, err := blockToLightClientHeaderCapella(context.Background(), block)
if err != nil {
return nil, errors.Wrap(err, "could not get capella header")
}
return &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderCapella{
HeaderCapella: capellaHeader,
},
}, nil
case version.Deneb, version.Electra:
denebHeader, err := blockToLightClientHeaderDeneb(context.Background(), block)
if err != nil {
return nil, errors.Wrap(err, "could not get header")
}
return &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderDeneb{
HeaderDeneb: denebHeader,
},
}, nil
default:
return nil, fmt.Errorf("unsupported block version %s", version.String(block.Version()))
}
}
func blockToLightClientHeaderAltair(block interfaces.ReadOnlySignedBeaconBlock) (*ethpbv2.LightClientHeader, error) {
if block.Version() < version.Altair {
return nil, fmt.Errorf("block version is %s instead of Altair", version.String(block.Version()))
}
@@ -692,8 +359,8 @@ func BlockToLightClientHeaderAltair(block interfaces.ReadOnlySignedBeaconBlock)
}, nil
}
func BlockToLightClientHeaderCapella(ctx context.Context, block interfaces.ReadOnlySignedBeaconBlock) (*ethpbv2.LightClientHeaderCapella, error) {
if block.Version() != version.Capella {
func blockToLightClientHeaderCapella(ctx context.Context, block interfaces.ReadOnlySignedBeaconBlock) (*ethpbv2.LightClientHeaderCapella, error) {
if block.Version() < version.Capella {
return nil, fmt.Errorf("block version is %s instead of Capella", version.String(block.Version()))
}
@@ -754,9 +421,9 @@ func BlockToLightClientHeaderCapella(ctx context.Context, block interfaces.ReadO
}, nil
}
func BlockToLightClientHeaderDeneb(ctx context.Context, block interfaces.ReadOnlySignedBeaconBlock) (*ethpbv2.LightClientHeaderDeneb, error) {
if block.Version() != version.Deneb {
return nil, fmt.Errorf("block version is %s instead of Deneb", version.String(block.Version()))
func blockToLightClientHeaderDeneb(ctx context.Context, block interfaces.ReadOnlySignedBeaconBlock) (*ethpbv2.LightClientHeaderDeneb, error) {
if block.Version() < version.Deneb {
return nil, fmt.Errorf("block version is %s instead of Deneb/Electra", version.String(block.Version()))
}
payload, err := block.Block().Body().Execution()

File diff suppressed because it is too large Load Diff

View File

@@ -73,7 +73,7 @@ type goodNotifier struct {
MockStateFeed *event.Feed
}
func (g *goodNotifier) StateFeed() *event.Feed {
func (g *goodNotifier) StateFeed() event.SubscriberSender {
if g.MockStateFeed == nil {
g.MockStateFeed = new(event.Feed)
}

View File

@@ -398,7 +398,7 @@ func initSyncWaiter(ctx context.Context, complete chan struct{}) func() error {
}
// StateFeed implements statefeed.Notifier.
func (b *BeaconNode) StateFeed() *event.Feed {
func (b *BeaconNode) StateFeed() event.SubscriberSender {
return b.stateFeed
}
@@ -408,7 +408,7 @@ func (b *BeaconNode) BlockFeed() *event.Feed {
}
// OperationFeed implements opfeed.Notifier.
func (b *BeaconNode) OperationFeed() *event.Feed {
func (b *BeaconNode) OperationFeed() event.SubscriberSender {
return b.opFeed
}

View File

@@ -89,5 +89,6 @@ go_test(
"//testing/require:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
"@org_golang_x_exp//maps:go_default_library",
],
)

View File

@@ -773,6 +773,15 @@ func (s *Service) beaconEndpoints(
handler: server.GetValidatorBalances,
methods: []string{http.MethodGet, http.MethodPost},
},
{
template: "/eth/v1/beacon/deposit_snapshot",
name: namespace + ".GetDepositSnapshot",
middleware: []middleware.Middleware{
middleware.AcceptHeaderHandler([]string{api.JsonMediaType}),
},
handler: server.GetDepositSnapshot,
methods: []string{http.MethodGet},
},
}
}
@@ -942,6 +951,8 @@ func (s *Service) prysmBeaconEndpoints(
ChainInfoFetcher: s.cfg.ChainInfoFetcher,
FinalizationFetcher: s.cfg.FinalizationFetcher,
CoreService: coreService,
Broadcaster: s.cfg.Broadcaster,
BlobReceiver: s.cfg.BlobReceiver,
}
const namespace = "prysm.beacon"
@@ -992,6 +1003,16 @@ func (s *Service) prysmBeaconEndpoints(
handler: server.GetChainHead,
methods: []string{http.MethodGet},
},
{
template: "/prysm/v1/beacon/blobs",
name: namespace + ".PublishBlobs",
middleware: []middleware.Middleware{
middleware.ContentTypeHandler([]string{api.JsonMediaType}),
middleware.AcceptHeaderHandler([]string{api.JsonMediaType}),
},
handler: server.PublishBlobs,
methods: []string{http.MethodPost},
},
}
}

View File

@@ -2,9 +2,11 @@ package rpc
import (
"net/http"
"slices"
"testing"
"github.com/prysmaticlabs/prysm/v5/testing/assert"
"golang.org/x/exp/maps"
)
func Test_endpoints(t *testing.T) {
@@ -31,7 +33,6 @@ func Test_endpoints(t *testing.T) {
"/eth/v2/beacon/blinded_blocks": {http.MethodPost},
"/eth/v1/beacon/blocks": {http.MethodPost},
"/eth/v2/beacon/blocks": {http.MethodPost},
"/eth/v1/beacon/blocks/{block_id}": {http.MethodGet},
"/eth/v2/beacon/blocks/{block_id}": {http.MethodGet},
"/eth/v1/beacon/blocks/{block_id}/root": {http.MethodGet},
"/eth/v1/beacon/blocks/{block_id}/attestations": {http.MethodGet},
@@ -69,7 +70,6 @@ func Test_endpoints(t *testing.T) {
}
debugRoutes := map[string][]string{
"/eth/v1/debug/beacon/states/{state_id}": {http.MethodGet},
"/eth/v2/debug/beacon/states/{state_id}": {http.MethodGet},
"/eth/v2/debug/beacon/heads": {http.MethodGet},
"/eth/v1/debug/fork_choice": {http.MethodGet},
@@ -115,6 +115,7 @@ func Test_endpoints(t *testing.T) {
"/eth/v1/beacon/states/{state_id}/validator_count": {http.MethodGet},
"/prysm/v1/beacon/states/{state_id}/validator_count": {http.MethodGet},
"/prysm/v1/beacon/chain_head": {http.MethodGet},
"/prysm/v1/beacon/blobs": {http.MethodPost},
}
prysmNodeRoutes := map[string][]string{
@@ -133,22 +134,18 @@ func Test_endpoints(t *testing.T) {
s := &Service{cfg: &Config{}}
routesMap := combineMaps(beaconRoutes, builderRoutes, configRoutes, debugRoutes, eventsRoutes, nodeRoutes, validatorRoutes, rewardsRoutes, lightClientRoutes, blobRoutes, prysmValidatorRoutes, prysmNodeRoutes, prysmBeaconRoutes)
actual := s.endpoints(true, nil, nil, nil, nil, nil, nil)
for _, e := range actual {
methods, ok := routesMap[e.template]
assert.Equal(t, true, ok, "endpoint "+e.template+" not found")
if ok {
for _, em := range e.methods {
methodFound := false
for _, m := range methods {
if m == em {
methodFound = true
break
}
}
assert.Equal(t, true, methodFound, "method "+em+" for endpoint "+e.template+" not found")
}
endpoints := s.endpoints(true, nil, nil, nil, nil, nil, nil)
actualRoutes := make(map[string][]string, len(endpoints))
for _, e := range endpoints {
if _, ok := actualRoutes[e.template]; ok {
actualRoutes[e.template] = append(actualRoutes[e.template], e.methods...)
} else {
actualRoutes[e.template] = e.methods
}
}
expectedRoutes := combineMaps(beaconRoutes, builderRoutes, configRoutes, debugRoutes, eventsRoutes, nodeRoutes, validatorRoutes, rewardsRoutes, lightClientRoutes, blobRoutes, prysmValidatorRoutes, prysmNodeRoutes, prysmBeaconRoutes)
assert.Equal(t, true, maps.EqualFunc(expectedRoutes, actualRoutes, func(actualMethods []string, expectedMethods []string) bool {
return slices.Equal(expectedMethods, actualMethods)
}))
}

View File

@@ -1512,10 +1512,6 @@ func (s *Server) GetDepositSnapshot(w http.ResponseWriter, r *http.Request) {
ctx, span := trace.StartSpan(r.Context(), "beacon.GetDepositSnapshot")
defer span.End()
if s.BeaconDB == nil {
httputil.HandleError(w, "Could not retrieve beaconDB", http.StatusInternalServerError)
return
}
eth1data, err := s.BeaconDB.ExecutionChainData(ctx)
if err != nil {
httputil.HandleError(w, "Could not retrieve execution chain data: "+err.Error(), http.StatusInternalServerError)
@@ -1527,7 +1523,7 @@ func (s *Server) GetDepositSnapshot(w http.ResponseWriter, r *http.Request) {
}
snapshot := eth1data.DepositSnapshot
if snapshot == nil || len(snapshot.Finalized) == 0 {
httputil.HandleError(w, "No Finalized Snapshot Available", http.StatusNotFound)
httputil.HandleError(w, "No finalized snapshot available", http.StatusNotFound)
return
}
if len(snapshot.Finalized) > depositsnapshot.DepositContractDepth {

View File

@@ -268,6 +268,38 @@ func TestGetBlockV2(t *testing.T) {
require.NoError(t, err)
assert.DeepEqual(t, blk, b)
})
t.Run("electra", func(t *testing.T) {
b := util.NewBeaconBlockElectra()
b.Block.Slot = 123
sb, err := blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
mockBlockFetcher := &testutil.MockBlocker{BlockToReturn: sb}
mockChainService := &chainMock.ChainService{
FinalizedRoots: map[[32]byte]bool{},
}
s := &Server{
OptimisticModeFetcher: mockChainService,
FinalizationFetcher: mockChainService,
Blocker: mockBlockFetcher,
}
request := httptest.NewRequest(http.MethodGet, "http://foo.example/eth/v2/beacon/blocks/{block_id}", nil)
request.SetPathValue("block_id", "head")
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.GetBlockV2(writer, request)
require.Equal(t, http.StatusOK, writer.Code)
resp := &structs.GetBlockV2Response{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
assert.Equal(t, version.String(version.Electra), resp.Version)
sbb := &structs.SignedBeaconBlockElectra{Message: &structs.BeaconBlockElectra{}}
require.NoError(t, json.Unmarshal(resp.Data.Message, sbb.Message))
sbb.Signature = resp.Data.Signature
blk, err := sbb.ToConsensus()
require.NoError(t, err)
assert.DeepEqual(t, blk, b)
})
t.Run("execution optimistic", func(t *testing.T) {
b := util.NewBeaconBlockBellatrix()
sb, err := blocks.NewSignedBeaconBlock(b)
@@ -461,7 +493,29 @@ func TestGetBlockSSZV2(t *testing.T) {
require.NoError(t, err)
assert.DeepEqual(t, sszExpected, writer.Body.Bytes())
})
t.Run("electra", func(t *testing.T) {
b := util.NewBeaconBlockElectra()
b.Block.Slot = 123
sb, err := blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
s := &Server{
Blocker: &testutil.MockBlocker{BlockToReturn: sb},
}
request := httptest.NewRequest(http.MethodGet, "http://foo.example/eth/v2/beacon/blocks/{block_id}", nil)
request.SetPathValue("block_id", "head")
request.Header.Set("Accept", api.OctetStreamMediaType)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.GetBlockV2(writer, request)
require.Equal(t, http.StatusOK, writer.Code)
assert.Equal(t, version.String(version.Electra), writer.Header().Get(api.VersionHeader))
sszExpected, err := b.MarshalSSZ()
require.NoError(t, err)
assert.DeepEqual(t, sszExpected, writer.Body.Bytes())
})
}
func TestGetBlockAttestations(t *testing.T) {
@@ -759,6 +813,35 @@ func TestGetBlindedBlock(t *testing.T) {
require.NoError(t, err)
assert.DeepEqual(t, blk, b)
})
t.Run("electra", func(t *testing.T) {
b := util.NewBlindedBeaconBlockElectra()
sb, err := blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
mockChainService := &chainMock.ChainService{}
s := &Server{
OptimisticModeFetcher: mockChainService,
FinalizationFetcher: mockChainService,
Blocker: &testutil.MockBlocker{BlockToReturn: sb},
}
request := httptest.NewRequest(http.MethodGet, "http://foo.example/eth/v1/beacon/blinded_blocks/{block_id}", nil)
request.SetPathValue("block_id", "head")
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.GetBlindedBlock(writer, request)
require.Equal(t, http.StatusOK, writer.Code)
resp := &structs.GetBlockV2Response{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
assert.Equal(t, version.String(version.Electra), resp.Version)
sbb := &structs.SignedBlindedBeaconBlockElectra{Message: &structs.BlindedBeaconBlockElectra{}}
require.NoError(t, json.Unmarshal(resp.Data.Message, sbb.Message))
sbb.Signature = resp.Data.Signature
blk, err := sbb.ToConsensus()
require.NoError(t, err)
assert.DeepEqual(t, blk, b)
})
t.Run("execution optimistic", func(t *testing.T) {
b := util.NewBlindedBeaconBlockBellatrix()
sb, err := blocks.NewSignedBeaconBlock(b)

View File

@@ -20,6 +20,7 @@ go_library(
"//beacon-chain/core/time:go_default_library",
"//beacon-chain/core/transition:go_default_library",
"//config/params:go_default_library",
"//consensus-types/primitives:go_default_library",
"//monitoring/tracing/trace:go_default_library",
"//network/httputil:go_default_library",
"//proto/eth/v1:go_default_library",
@@ -29,12 +30,16 @@ go_library(
"//time/slots:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["events_test.go"],
srcs = [
"events_test.go",
"http_test.go",
],
embed = [":go_default_library"],
deps = [
"//beacon-chain/blockchain/testing:go_default_library",
@@ -49,9 +54,9 @@ go_test(
"//consensus-types/primitives:go_default_library",
"//proto/eth/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//testing/assert:go_default_library",
"//testing/require:go_default_library",
"//testing/util:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_r3labs_sse_v2//:go_default_library",
],
)

View File

@@ -1,24 +1,26 @@
package events
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
time2 "time"
"time"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v5/api"
"github.com/prysmaticlabs/prysm/v5/api/server/structs"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/blockchain"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/feed"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/feed/operation"
statefeed "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/feed/state"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time"
chaintime "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/transition"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
"github.com/prysmaticlabs/prysm/v5/network/httputil"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/eth/v1"
@@ -26,9 +28,13 @@ import (
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/prysmaticlabs/prysm/v5/time/slots"
log "github.com/sirupsen/logrus"
)
const DefaultEventFeedDepth = 1000
const (
InvalidTopic = "__invalid__"
// HeadTopic represents a new chain head event topic.
HeadTopic = "head"
// BlockTopic represents a new produced block event topic.
@@ -59,25 +65,83 @@ const (
LightClientOptimisticUpdateTopic = "light_client_optimistic_update"
)
const topicDataMismatch = "Event data type %T does not correspond to event topic %s"
var (
errInvalidTopicName = errors.New("invalid topic name")
errNoValidTopics = errors.New("no valid topics specified")
errSlowReader = errors.New("client failed to read fast enough to keep outgoing buffer below threshold")
errNotRequested = errors.New("event not requested by client")
errUnhandledEventData = errors.New("unable to represent event data in the event stream")
)
const chanBuffer = 1000
// StreamingResponseWriter defines a type that can be used by the eventStreamer.
// This must be an http.ResponseWriter that supports flushing and hijacking.
type StreamingResponseWriter interface {
http.ResponseWriter
http.Flusher
}
var casesHandled = map[string]bool{
HeadTopic: true,
BlockTopic: true,
AttestationTopic: true,
VoluntaryExitTopic: true,
FinalizedCheckpointTopic: true,
ChainReorgTopic: true,
SyncCommitteeContributionTopic: true,
BLSToExecutionChangeTopic: true,
PayloadAttributesTopic: true,
BlobSidecarTopic: true,
ProposerSlashingTopic: true,
AttesterSlashingTopic: true,
LightClientFinalityUpdateTopic: true,
LightClientOptimisticUpdateTopic: true,
// The eventStreamer uses lazyReaders to defer serialization until the moment the value is ready to be written to the client.
type lazyReader func() io.Reader
var opsFeedEventTopics = map[feed.EventType]string{
operation.AggregatedAttReceived: AttestationTopic,
operation.UnaggregatedAttReceived: AttestationTopic,
operation.ExitReceived: VoluntaryExitTopic,
operation.SyncCommitteeContributionReceived: SyncCommitteeContributionTopic,
operation.BLSToExecutionChangeReceived: BLSToExecutionChangeTopic,
operation.BlobSidecarReceived: BlobSidecarTopic,
operation.AttesterSlashingReceived: AttesterSlashingTopic,
operation.ProposerSlashingReceived: ProposerSlashingTopic,
}
var stateFeedEventTopics = map[feed.EventType]string{
statefeed.NewHead: HeadTopic,
statefeed.MissedSlot: PayloadAttributesTopic,
statefeed.FinalizedCheckpoint: FinalizedCheckpointTopic,
statefeed.LightClientFinalityUpdate: LightClientFinalityUpdateTopic,
statefeed.LightClientOptimisticUpdate: LightClientOptimisticUpdateTopic,
statefeed.Reorg: ChainReorgTopic,
statefeed.BlockProcessed: BlockTopic,
}
var topicsForStateFeed = topicsForFeed(stateFeedEventTopics)
var topicsForOpsFeed = topicsForFeed(opsFeedEventTopics)
func topicsForFeed(em map[feed.EventType]string) map[string]bool {
topics := make(map[string]bool, len(em))
for _, topic := range em {
topics[topic] = true
}
return topics
}
type topicRequest struct {
topics map[string]bool
needStateFeed bool
needOpsFeed bool
}
func (req *topicRequest) requested(topic string) bool {
return req.topics[topic]
}
func newTopicRequest(topics []string) (*topicRequest, error) {
req := &topicRequest{topics: make(map[string]bool)}
for _, name := range topics {
if topicsForStateFeed[name] {
req.needStateFeed = true
} else if topicsForOpsFeed[name] {
req.needOpsFeed = true
} else {
return nil, errors.Wrapf(errInvalidTopicName, name)
}
req.topics[name] = true
}
if len(req.topics) == 0 || (!req.needStateFeed && !req.needOpsFeed) {
return nil, errNoValidTopics
}
return req, nil
}
// StreamEvents provides an endpoint to subscribe to the beacon node Server-Sent-Events stream.
@@ -88,326 +152,412 @@ func (s *Server) StreamEvents(w http.ResponseWriter, r *http.Request) {
ctx, span := trace.StartSpan(r.Context(), "events.StreamEvents")
defer span.End()
flusher, ok := w.(http.Flusher)
topics, err := newTopicRequest(r.URL.Query()["topics"])
if err != nil {
httputil.HandleError(w, err.Error(), http.StatusBadRequest)
return
}
sw, ok := w.(StreamingResponseWriter)
if !ok {
httputil.HandleError(w, "Streaming unsupported!", http.StatusInternalServerError)
msg := "beacon node misconfiguration: http stack may not support required response handling features, like flushing"
httputil.HandleError(w, msg, http.StatusInternalServerError)
return
}
topics := r.URL.Query()["topics"]
if len(topics) == 0 {
httputil.HandleError(w, "No topics specified to subscribe to", http.StatusBadRequest)
return
depth := s.EventFeedDepth
if depth == 0 {
depth = DefaultEventFeedDepth
}
topicsMap := make(map[string]bool)
for _, topic := range topics {
if _, ok := casesHandled[topic]; !ok {
httputil.HandleError(w, fmt.Sprintf("Invalid topic: %s", topic), http.StatusBadRequest)
return
}
topicsMap[topic] = true
}
// Subscribe to event feeds from information received in the beacon node runtime.
opsChan := make(chan *feed.Event, chanBuffer)
opsSub := s.OperationNotifier.OperationFeed().Subscribe(opsChan)
stateChan := make(chan *feed.Event, chanBuffer)
stateSub := s.StateNotifier.StateFeed().Subscribe(stateChan)
defer opsSub.Unsubscribe()
defer stateSub.Unsubscribe()
// Set up SSE response headers
w.Header().Set("Content-Type", api.EventStreamMediaType)
w.Header().Set("Connection", api.KeepAlive)
// Handle each event received and context cancellation.
// We send a keepalive dummy message immediately to prevent clients
// stalling while waiting for the first response chunk.
// After that we send a keepalive dummy message every SECONDS_PER_SLOT
// to prevent anyone (e.g. proxy servers) from closing connections.
if err := sendKeepalive(w, flusher); err != nil {
es, err := newEventStreamer(depth, s.KeepAliveInterval)
if err != nil {
httputil.HandleError(w, err.Error(), http.StatusInternalServerError)
return
}
keepaliveTicker := time2.NewTicker(time2.Duration(params.BeaconConfig().SecondsPerSlot) * time2.Second)
ctx, cancel := context.WithCancel(ctx)
defer cancel()
api.SetSSEHeaders(sw)
go es.outboxWriteLoop(ctx, cancel, sw)
if err := es.recvEventLoop(ctx, cancel, topics, s); err != nil {
log.WithError(err).Debug("Shutting down StreamEvents handler.")
}
}
func newEventStreamer(buffSize int, ka time.Duration) (*eventStreamer, error) {
if ka == 0 {
ka = time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second
}
return &eventStreamer{
outbox: make(chan lazyReader, buffSize),
keepAlive: ka,
}, nil
}
type eventStreamer struct {
outbox chan lazyReader
keepAlive time.Duration
}
func (es *eventStreamer) recvEventLoop(ctx context.Context, cancel context.CancelFunc, req *topicRequest, s *Server) error {
eventsChan := make(chan *feed.Event, len(es.outbox))
if req.needOpsFeed {
opsSub := s.OperationNotifier.OperationFeed().Subscribe(eventsChan)
defer opsSub.Unsubscribe()
}
if req.needStateFeed {
stateSub := s.StateNotifier.StateFeed().Subscribe(eventsChan)
defer stateSub.Unsubscribe()
}
for {
select {
case event := <-opsChan:
if err := handleBlockOperationEvents(w, flusher, topicsMap, event); err != nil {
httputil.HandleError(w, err.Error(), http.StatusInternalServerError)
return
}
case event := <-stateChan:
if err := s.handleStateEvents(ctx, w, flusher, topicsMap, event); err != nil {
httputil.HandleError(w, err.Error(), http.StatusInternalServerError)
return
}
case <-keepaliveTicker.C:
if err := sendKeepalive(w, flusher); err != nil {
httputil.HandleError(w, err.Error(), http.StatusInternalServerError)
return
}
case <-ctx.Done():
return ctx.Err()
case event := <-eventsChan:
lr, err := s.lazyReaderForEvent(ctx, event, req)
if err != nil {
if !errors.Is(err, errNotRequested) {
log.WithField("event_type", fmt.Sprintf("%v", event.Data)).WithError(err).Error("StreamEvents API endpoint received an event it was unable to handle.")
}
continue
}
// If the client can't keep up, the outbox will eventually completely fill, at which
// safeWrite will error, and we'll hit the below return statement, at which point the deferred
// Unsuscribe calls will be made and the event feed will stop writing to this channel.
// Since the outbox and event stream channels are separately buffered, the event subscription
// channel should stay relatively empty, which gives this loop time to unsubscribe
// and cleanup before the event stream channel fills and disrupts other readers.
if err := es.safeWrite(ctx, lr); err != nil {
cancel()
// note: we could hijack the connection and close it here. Does that cause issues? What are the benefits?
// A benefit of hijack and close is that it may force an error on the remote end, however just closing the context of the
// http handler may be sufficient to cause the remote http response reader to close.
if errors.Is(err, errSlowReader) {
log.WithError(err).Warn("Client is unable to keep up with event stream, shutting down.")
}
return err
}
}
}
}
func (es *eventStreamer) safeWrite(ctx context.Context, rf func() io.Reader) error {
if rf == nil {
return nil
}
select {
case <-ctx.Done():
return ctx.Err()
case es.outbox <- rf:
return nil
default:
// If this is the case, the select case to write to the outbox could not proceed, meaning the outbox is full.
// If a reader can't keep up with the stream, we shut them down.
return errSlowReader
}
}
// newlineReader is used to write keep-alives to the client.
// keep-alives in the sse protocol are a single ':' colon followed by 2 newlines.
func newlineReader() io.Reader {
return bytes.NewBufferString(":\n\n")
}
// outboxWriteLoop runs in a separate goroutine. Its job is to write the values in the outbox to
// the client as fast as the client can read them.
func (es *eventStreamer) outboxWriteLoop(ctx context.Context, cancel context.CancelFunc, w StreamingResponseWriter) {
var err error
defer func() {
if err != nil {
log.WithError(err).Debug("Event streamer shutting down due to error.")
}
}()
defer cancel()
// Write a keepalive at the start to test the connection and simplify test setup.
if err = es.writeOutbox(ctx, w, nil); err != nil {
return
}
kaT := time.NewTimer(es.keepAlive)
// Ensure the keepalive timer is stopped and drained if it has fired.
defer func() {
if !kaT.Stop() {
<-kaT.C
}
}()
for {
select {
case <-ctx.Done():
err = ctx.Err()
return
case <-kaT.C:
if err = es.writeOutbox(ctx, w, nil); err != nil {
return
}
// In this case the timer doesn't need to be Stopped before the Reset call after the select statement,
// because the timer has already fired.
case lr := <-es.outbox:
if err = es.writeOutbox(ctx, w, lr); err != nil {
return
}
// We don't know if the timer fired concurrently to this case being ready, so we need to check the return
// of Stop and drain the timer channel if it fired. We won't need to do this in go 1.23.
if !kaT.Stop() {
<-kaT.C
}
}
kaT.Reset(es.keepAlive)
}
}
func (es *eventStreamer) writeOutbox(ctx context.Context, w StreamingResponseWriter, first lazyReader) error {
needKeepAlive := true
if first != nil {
if _, err := io.Copy(w, first()); err != nil {
return err
}
needKeepAlive = false
}
// While the first event was being read by the client, further events may be queued in the outbox.
// We can drain them right away rather than go back out to the outer select statement, where the keepAlive timer
// may have fired, triggering an unnecessary extra keep-alive write and flush.
for {
select {
case <-ctx.Done():
return ctx.Err()
case rf := <-es.outbox:
if _, err := io.Copy(w, rf()); err != nil {
return err
}
needKeepAlive = false
default:
if needKeepAlive {
if _, err := io.Copy(w, newlineReader()); err != nil {
return err
}
}
w.Flush()
return nil
}
}
}
func handleBlockOperationEvents(w http.ResponseWriter, flusher http.Flusher, requestedTopics map[string]bool, event *feed.Event) error {
switch event.Type {
case operation.AggregatedAttReceived:
if _, ok := requestedTopics[AttestationTopic]; !ok {
return nil
}
attData, ok := event.Data.(*operation.AggregatedAttReceivedData)
if !ok {
return write(w, flusher, topicDataMismatch, event.Data, AttestationTopic)
}
att := structs.AttFromConsensus(attData.Attestation.Aggregate)
return send(w, flusher, AttestationTopic, att)
case operation.UnaggregatedAttReceived:
if _, ok := requestedTopics[AttestationTopic]; !ok {
return nil
}
attData, ok := event.Data.(*operation.UnAggregatedAttReceivedData)
if !ok {
return write(w, flusher, topicDataMismatch, event.Data, AttestationTopic)
}
a, ok := attData.Attestation.(*eth.Attestation)
if !ok {
return write(w, flusher, topicDataMismatch, event.Data, AttestationTopic)
}
att := structs.AttFromConsensus(a)
return send(w, flusher, AttestationTopic, att)
case operation.ExitReceived:
if _, ok := requestedTopics[VoluntaryExitTopic]; !ok {
return nil
}
exitData, ok := event.Data.(*operation.ExitReceivedData)
if !ok {
return write(w, flusher, topicDataMismatch, event.Data, VoluntaryExitTopic)
}
exit := structs.SignedExitFromConsensus(exitData.Exit)
return send(w, flusher, VoluntaryExitTopic, exit)
case operation.SyncCommitteeContributionReceived:
if _, ok := requestedTopics[SyncCommitteeContributionTopic]; !ok {
return nil
}
contributionData, ok := event.Data.(*operation.SyncCommitteeContributionReceivedData)
if !ok {
return write(w, flusher, topicDataMismatch, event.Data, SyncCommitteeContributionTopic)
}
contribution := structs.SignedContributionAndProofFromConsensus(contributionData.Contribution)
return send(w, flusher, SyncCommitteeContributionTopic, contribution)
case operation.BLSToExecutionChangeReceived:
if _, ok := requestedTopics[BLSToExecutionChangeTopic]; !ok {
return nil
}
changeData, ok := event.Data.(*operation.BLSToExecutionChangeReceivedData)
if !ok {
return write(w, flusher, topicDataMismatch, event.Data, BLSToExecutionChangeTopic)
}
return send(w, flusher, BLSToExecutionChangeTopic, structs.SignedBLSChangeFromConsensus(changeData.Change))
case operation.BlobSidecarReceived:
if _, ok := requestedTopics[BlobSidecarTopic]; !ok {
return nil
}
blobData, ok := event.Data.(*operation.BlobSidecarReceivedData)
if !ok {
return write(w, flusher, topicDataMismatch, event.Data, BlobSidecarTopic)
}
versionedHash := blockchain.ConvertKzgCommitmentToVersionedHash(blobData.Blob.KzgCommitment)
blobEvent := &structs.BlobSidecarEvent{
BlockRoot: hexutil.Encode(blobData.Blob.BlockRootSlice()),
Index: fmt.Sprintf("%d", blobData.Blob.Index),
Slot: fmt.Sprintf("%d", blobData.Blob.Slot()),
VersionedHash: versionedHash.String(),
KzgCommitment: hexutil.Encode(blobData.Blob.KzgCommitment),
}
return send(w, flusher, BlobSidecarTopic, blobEvent)
case operation.AttesterSlashingReceived:
if _, ok := requestedTopics[AttesterSlashingTopic]; !ok {
return nil
}
attesterSlashingData, ok := event.Data.(*operation.AttesterSlashingReceivedData)
if !ok {
return write(w, flusher, topicDataMismatch, event.Data, AttesterSlashingTopic)
}
slashing, ok := attesterSlashingData.AttesterSlashing.(*eth.AttesterSlashing)
if ok {
return send(w, flusher, AttesterSlashingTopic, structs.AttesterSlashingFromConsensus(slashing))
}
// TODO: extend to Electra
case operation.ProposerSlashingReceived:
if _, ok := requestedTopics[ProposerSlashingTopic]; !ok {
return nil
}
proposerSlashingData, ok := event.Data.(*operation.ProposerSlashingReceivedData)
if !ok {
return write(w, flusher, topicDataMismatch, event.Data, ProposerSlashingTopic)
}
return send(w, flusher, ProposerSlashingTopic, structs.ProposerSlashingFromConsensus(proposerSlashingData.ProposerSlashing))
func jsonMarshalReader(name string, v any) io.Reader {
d, err := json.Marshal(v)
if err != nil {
log.WithError(err).WithField("type_name", fmt.Sprintf("%T", v)).Error("Could not marshal event data.")
return nil
}
return nil
return bytes.NewBufferString("event: " + name + "\ndata: " + string(d) + "\n\n")
}
func (s *Server) handleStateEvents(ctx context.Context, w http.ResponseWriter, flusher http.Flusher, requestedTopics map[string]bool, event *feed.Event) error {
switch event.Type {
case statefeed.NewHead:
if _, ok := requestedTopics[HeadTopic]; ok {
headData, ok := event.Data.(*ethpb.EventHead)
if !ok {
return write(w, flusher, topicDataMismatch, event.Data, HeadTopic)
}
head := &structs.HeadEvent{
Slot: fmt.Sprintf("%d", headData.Slot),
Block: hexutil.Encode(headData.Block),
State: hexutil.Encode(headData.State),
EpochTransition: headData.EpochTransition,
ExecutionOptimistic: headData.ExecutionOptimistic,
PreviousDutyDependentRoot: hexutil.Encode(headData.PreviousDutyDependentRoot),
CurrentDutyDependentRoot: hexutil.Encode(headData.CurrentDutyDependentRoot),
}
return send(w, flusher, HeadTopic, head)
func topicForEvent(event *feed.Event) string {
switch event.Data.(type) {
case *operation.AggregatedAttReceivedData:
return AttestationTopic
case *operation.UnAggregatedAttReceivedData:
return AttestationTopic
case *operation.ExitReceivedData:
return VoluntaryExitTopic
case *operation.SyncCommitteeContributionReceivedData:
return SyncCommitteeContributionTopic
case *operation.BLSToExecutionChangeReceivedData:
return BLSToExecutionChangeTopic
case *operation.BlobSidecarReceivedData:
return BlobSidecarTopic
case *operation.AttesterSlashingReceivedData:
return AttesterSlashingTopic
case *operation.ProposerSlashingReceivedData:
return ProposerSlashingTopic
case *ethpb.EventHead:
return HeadTopic
case *ethpb.EventFinalizedCheckpoint:
return FinalizedCheckpointTopic
case *ethpbv2.LightClientFinalityUpdateWithVersion:
return LightClientFinalityUpdateTopic
case *ethpbv2.LightClientOptimisticUpdateWithVersion:
return LightClientOptimisticUpdateTopic
case *ethpb.EventChainReorg:
return ChainReorgTopic
case *statefeed.BlockProcessedData:
return BlockTopic
default:
if event.Type == statefeed.MissedSlot {
return PayloadAttributesTopic
}
if _, ok := requestedTopics[PayloadAttributesTopic]; ok {
return s.sendPayloadAttributes(ctx, w, flusher)
}
case statefeed.MissedSlot:
if _, ok := requestedTopics[PayloadAttributesTopic]; ok {
return s.sendPayloadAttributes(ctx, w, flusher)
}
case statefeed.FinalizedCheckpoint:
if _, ok := requestedTopics[FinalizedCheckpointTopic]; !ok {
return nil
}
checkpointData, ok := event.Data.(*ethpb.EventFinalizedCheckpoint)
if !ok {
return write(w, flusher, topicDataMismatch, event.Data, FinalizedCheckpointTopic)
}
checkpoint := &structs.FinalizedCheckpointEvent{
Block: hexutil.Encode(checkpointData.Block),
State: hexutil.Encode(checkpointData.State),
Epoch: fmt.Sprintf("%d", checkpointData.Epoch),
ExecutionOptimistic: checkpointData.ExecutionOptimistic,
}
return send(w, flusher, FinalizedCheckpointTopic, checkpoint)
case statefeed.LightClientFinalityUpdate:
if _, ok := requestedTopics[LightClientFinalityUpdateTopic]; !ok {
return nil
}
updateData, ok := event.Data.(*ethpbv2.LightClientFinalityUpdateWithVersion)
if !ok {
return write(w, flusher, topicDataMismatch, event.Data, LightClientFinalityUpdateTopic)
}
update, err := structs.LightClientFinalityUpdateFromConsensus(updateData.Data)
if err != nil {
return err
}
updateEvent := &structs.LightClientFinalityUpdateEvent{
Version: version.String(int(updateData.Version)),
Data: update,
}
return send(w, flusher, LightClientFinalityUpdateTopic, updateEvent)
case statefeed.LightClientOptimisticUpdate:
if _, ok := requestedTopics[LightClientOptimisticUpdateTopic]; !ok {
return nil
}
updateData, ok := event.Data.(*ethpbv2.LightClientOptimisticUpdateWithVersion)
if !ok {
return write(w, flusher, topicDataMismatch, event.Data, LightClientOptimisticUpdateTopic)
}
update, err := structs.LightClientOptimisticUpdateFromConsensus(updateData.Data)
if err != nil {
return err
}
updateEvent := &structs.LightClientOptimisticUpdateEvent{
Version: version.String(int(updateData.Version)),
Data: update,
}
return send(w, flusher, LightClientOptimisticUpdateTopic, updateEvent)
case statefeed.Reorg:
if _, ok := requestedTopics[ChainReorgTopic]; !ok {
return nil
}
reorgData, ok := event.Data.(*ethpb.EventChainReorg)
if !ok {
return write(w, flusher, topicDataMismatch, event.Data, ChainReorgTopic)
}
reorg := &structs.ChainReorgEvent{
Slot: fmt.Sprintf("%d", reorgData.Slot),
Depth: fmt.Sprintf("%d", reorgData.Depth),
OldHeadBlock: hexutil.Encode(reorgData.OldHeadBlock),
NewHeadBlock: hexutil.Encode(reorgData.NewHeadBlock),
OldHeadState: hexutil.Encode(reorgData.OldHeadState),
NewHeadState: hexutil.Encode(reorgData.NewHeadState),
Epoch: fmt.Sprintf("%d", reorgData.Epoch),
ExecutionOptimistic: reorgData.ExecutionOptimistic,
}
return send(w, flusher, ChainReorgTopic, reorg)
case statefeed.BlockProcessed:
if _, ok := requestedTopics[BlockTopic]; !ok {
return nil
}
blkData, ok := event.Data.(*statefeed.BlockProcessedData)
if !ok {
return write(w, flusher, topicDataMismatch, event.Data, BlockTopic)
}
blockRoot, err := blkData.SignedBlock.Block().HashTreeRoot()
if err != nil {
return write(w, flusher, "Could not get block root: "+err.Error())
}
blk := &structs.BlockEvent{
Slot: fmt.Sprintf("%d", blkData.Slot),
Block: hexutil.Encode(blockRoot[:]),
ExecutionOptimistic: blkData.Optimistic,
}
return send(w, flusher, BlockTopic, blk)
return InvalidTopic
}
}
func (s *Server) lazyReaderForEvent(ctx context.Context, event *feed.Event, topics *topicRequest) (lazyReader, error) {
eventName := topicForEvent(event)
if !topics.requested(eventName) {
return nil, errNotRequested
}
if eventName == PayloadAttributesTopic {
return s.currentPayloadAttributes(ctx)
}
if event == nil || event.Data == nil {
return nil, errors.New("event or event data is nil")
}
switch v := event.Data.(type) {
case *ethpb.EventHead:
// The head event is a special case because, if the client requested the payload attributes topic,
// we send two event messages in reaction; the head event and the payload attributes.
headReader := func() io.Reader {
return jsonMarshalReader(eventName, structs.HeadEventFromV1(v))
}
// Don't do the expensive attr lookup unless the client requested it.
if !topics.requested(PayloadAttributesTopic) {
return headReader, nil
}
// Since payload attributes could change before the outbox is written, we need to do a blocking operation to
// get the current payload attributes right here.
attrReader, err := s.currentPayloadAttributes(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not get payload attributes for head event")
}
return func() io.Reader {
return io.MultiReader(headReader(), attrReader())
}, nil
case *operation.AggregatedAttReceivedData:
return func() io.Reader {
att := structs.AttFromConsensus(v.Attestation.Aggregate)
return jsonMarshalReader(eventName, att)
}, nil
case *operation.UnAggregatedAttReceivedData:
att, ok := v.Attestation.(*eth.Attestation)
if !ok {
return nil, errors.Wrapf(errUnhandledEventData, "Unexpected type %T for the .Attestation field of UnAggregatedAttReceivedData", v.Attestation)
}
return func() io.Reader {
att := structs.AttFromConsensus(att)
return jsonMarshalReader(eventName, att)
}, nil
case *operation.ExitReceivedData:
return func() io.Reader {
return jsonMarshalReader(eventName, structs.SignedExitFromConsensus(v.Exit))
}, nil
case *operation.SyncCommitteeContributionReceivedData:
return func() io.Reader {
return jsonMarshalReader(eventName, structs.SignedContributionAndProofFromConsensus(v.Contribution))
}, nil
case *operation.BLSToExecutionChangeReceivedData:
return func() io.Reader {
return jsonMarshalReader(eventName, structs.SignedBLSChangeFromConsensus(v.Change))
}, nil
case *operation.BlobSidecarReceivedData:
return func() io.Reader {
versionedHash := primitives.ConvertKzgCommitmentToVersionedHash(v.Blob.KzgCommitment)
return jsonMarshalReader(eventName, &structs.BlobSidecarEvent{
BlockRoot: hexutil.Encode(v.Blob.BlockRootSlice()),
Index: fmt.Sprintf("%d", v.Blob.Index),
Slot: fmt.Sprintf("%d", v.Blob.Slot()),
VersionedHash: versionedHash.String(),
KzgCommitment: hexutil.Encode(v.Blob.KzgCommitment),
})
}, nil
case *operation.AttesterSlashingReceivedData:
slashing, ok := v.AttesterSlashing.(*eth.AttesterSlashing)
if !ok {
return nil, errors.Wrapf(errUnhandledEventData, "Unexpected type %T for the .AttesterSlashing field of AttesterSlashingReceivedData", v.AttesterSlashing)
}
return func() io.Reader {
return jsonMarshalReader(eventName, structs.AttesterSlashingFromConsensus(slashing))
}, nil
case *operation.ProposerSlashingReceivedData:
return func() io.Reader {
return jsonMarshalReader(eventName, structs.ProposerSlashingFromConsensus(v.ProposerSlashing))
}, nil
case *ethpb.EventFinalizedCheckpoint:
return func() io.Reader {
return jsonMarshalReader(eventName, structs.FinalizedCheckpointEventFromV1(v))
}, nil
case *ethpbv2.LightClientFinalityUpdateWithVersion:
cv, err := structs.LightClientFinalityUpdateFromConsensus(v.Data)
if err != nil {
return nil, errors.Wrap(err, "LightClientFinalityUpdateWithVersion event conversion failure")
}
ev := &structs.LightClientFinalityUpdateEvent{
Version: version.String(int(v.Version)),
Data: cv,
}
return func() io.Reader {
return jsonMarshalReader(eventName, ev)
}, nil
case *ethpbv2.LightClientOptimisticUpdateWithVersion:
cv, err := structs.LightClientOptimisticUpdateFromConsensus(v.Data)
if err != nil {
return nil, errors.Wrap(err, "LightClientOptimisticUpdateWithVersion event conversion failure")
}
ev := &structs.LightClientOptimisticUpdateEvent{
Version: version.String(int(v.Version)),
Data: cv,
}
return func() io.Reader {
return jsonMarshalReader(eventName, ev)
}, nil
case *ethpb.EventChainReorg:
return func() io.Reader {
return jsonMarshalReader(eventName, structs.EventChainReorgFromV1(v))
}, nil
case *statefeed.BlockProcessedData:
blockRoot, err := v.SignedBlock.Block().HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "could not compute block root for BlockProcessedData state feed event")
}
return func() io.Reader {
blk := &structs.BlockEvent{
Slot: fmt.Sprintf("%d", v.Slot),
Block: hexutil.Encode(blockRoot[:]),
ExecutionOptimistic: v.Optimistic,
}
return jsonMarshalReader(eventName, blk)
}, nil
default:
return nil, errors.Wrapf(errUnhandledEventData, "event data type %T unsupported", v)
}
return nil
}
// This event stream is intended to be used by builders and relays.
// Parent fields are based on state at N_{current_slot}, while the rest of fields are based on state of N_{current_slot + 1}
func (s *Server) sendPayloadAttributes(ctx context.Context, w http.ResponseWriter, flusher http.Flusher) error {
func (s *Server) currentPayloadAttributes(ctx context.Context) (lazyReader, error) {
headRoot, err := s.HeadFetcher.HeadRoot(ctx)
if err != nil {
return write(w, flusher, "Could not get head root: "+err.Error())
return nil, errors.Wrap(err, "could not get head root")
}
st, err := s.HeadFetcher.HeadState(ctx)
if err != nil {
return write(w, flusher, "Could not get head state: "+err.Error())
return nil, errors.Wrap(err, "could not get head state")
}
// advance the head state
headState, err := transition.ProcessSlotsIfPossible(ctx, st, s.ChainInfoFetcher.CurrentSlot()+1)
if err != nil {
return write(w, flusher, "Could not advance head state: "+err.Error())
return nil, errors.Wrap(err, "could not advance head state")
}
headBlock, err := s.HeadFetcher.HeadBlock(ctx)
if err != nil {
return write(w, flusher, "Could not get head block: "+err.Error())
return nil, errors.Wrap(err, "could not get head block")
}
headPayload, err := headBlock.Block().Body().Execution()
if err != nil {
return write(w, flusher, "Could not get execution payload: "+err.Error())
return nil, errors.Wrap(err, "could not get execution payload")
}
t, err := slots.ToTime(headState.GenesisTime(), headState.Slot())
if err != nil {
return write(w, flusher, "Could not get head state slot time: "+err.Error())
return nil, errors.Wrap(err, "could not get head state slot time")
}
prevRando, err := helpers.RandaoMix(headState, time.CurrentEpoch(headState))
prevRando, err := helpers.RandaoMix(headState, chaintime.CurrentEpoch(headState))
if err != nil {
return write(w, flusher, "Could not get head state randao mix: "+err.Error())
return nil, errors.Wrap(err, "could not get head state randao mix")
}
proposerIndex, err := helpers.BeaconProposerIndex(ctx, headState)
if err != nil {
return write(w, flusher, "Could not get head state proposer index: "+err.Error())
return nil, errors.Wrap(err, "could not get head state proposer index")
}
feeRecipient := params.BeaconConfig().DefaultFeeRecipient.Bytes()
tValidator, exists := s.TrackedValidatorsCache.Validator(proposerIndex)
@@ -425,7 +575,7 @@ func (s *Server) sendPayloadAttributes(ctx context.Context, w http.ResponseWrite
case version.Capella:
withdrawals, _, err := headState.ExpectedWithdrawals()
if err != nil {
return write(w, flusher, "Could not get head state expected withdrawals: "+err.Error())
return nil, errors.Wrap(err, "could not get head state expected withdrawals")
}
attributes = &structs.PayloadAttributesV2{
Timestamp: fmt.Sprintf("%d", t.Unix()),
@@ -436,11 +586,11 @@ func (s *Server) sendPayloadAttributes(ctx context.Context, w http.ResponseWrite
case version.Deneb, version.Electra:
withdrawals, _, err := headState.ExpectedWithdrawals()
if err != nil {
return write(w, flusher, "Could not get head state expected withdrawals: "+err.Error())
return nil, errors.Wrap(err, "could not get head state expected withdrawals")
}
parentRoot, err := headBlock.Block().HashTreeRoot()
if err != nil {
return write(w, flusher, "Could not get head block root: "+err.Error())
return nil, errors.Wrap(err, "could not get head block root")
}
attributes = &structs.PayloadAttributesV3{
Timestamp: fmt.Sprintf("%d", t.Unix()),
@@ -450,12 +600,12 @@ func (s *Server) sendPayloadAttributes(ctx context.Context, w http.ResponseWrite
ParentBeaconBlockRoot: hexutil.Encode(parentRoot[:]),
}
default:
return write(w, flusher, "Payload version %s is not supported", version.String(headState.Version()))
return nil, errors.Wrapf(err, "Payload version %s is not supported", version.String(headState.Version()))
}
attributesBytes, err := json.Marshal(attributes)
if err != nil {
return write(w, flusher, err.Error())
return nil, errors.Wrap(err, "errors marshaling payload attributes to json")
}
eventData := structs.PayloadAttributesEventData{
ProposerIndex: fmt.Sprintf("%d", proposerIndex),
@@ -467,31 +617,12 @@ func (s *Server) sendPayloadAttributes(ctx context.Context, w http.ResponseWrite
}
eventDataBytes, err := json.Marshal(eventData)
if err != nil {
return write(w, flusher, err.Error())
return nil, errors.Wrap(err, "errors marshaling payload attributes event data to json")
}
return send(w, flusher, PayloadAttributesTopic, &structs.PayloadAttributesEvent{
Version: version.String(headState.Version()),
Data: eventDataBytes,
})
}
func send(w http.ResponseWriter, flusher http.Flusher, name string, data interface{}) error {
j, err := json.Marshal(data)
if err != nil {
return write(w, flusher, "Could not marshal event to JSON: "+err.Error())
}
return write(w, flusher, "event: %s\ndata: %s\n\n", name, string(j))
}
func sendKeepalive(w http.ResponseWriter, flusher http.Flusher) error {
return write(w, flusher, ":\n\n")
}
func write(w http.ResponseWriter, flusher http.Flusher, format string, a ...any) error {
_, err := fmt.Fprintf(w, format, a...)
if err != nil {
return errors.Wrap(err, "could not write to response writer")
}
flusher.Flush()
return nil
return func() io.Reader {
return jsonMarshalReader(PayloadAttributesTopic, &structs.PayloadAttributesEvent{
Version: version.String(headState.Version()),
Data: eventDataBytes,
})
}, nil
}

View File

@@ -1,6 +1,7 @@
package events
import (
"context"
"fmt"
"io"
"math"
@@ -23,56 +24,99 @@ import (
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/eth/v1"
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/testing/assert"
"github.com/prysmaticlabs/prysm/v5/testing/require"
"github.com/prysmaticlabs/prysm/v5/testing/util"
sse "github.com/r3labs/sse/v2"
)
type flushableResponseRecorder struct {
*httptest.ResponseRecorder
flushed bool
func requireAllEventsReceived(t *testing.T, stn, opn *mockChain.EventFeedWrapper, events []*feed.Event, req *topicRequest, s *Server, w *StreamingResponseWriterRecorder) {
// maxBufferSize param copied from sse lib client code
sseR := sse.NewEventStreamReader(w.Body(), 1<<24)
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
expected := make(map[string]bool)
for i := range events {
ev := events[i]
// serialize the event the same way the server will so that we can compare expectation to results.
top := topicForEvent(ev)
eb, err := s.lazyReaderForEvent(context.Background(), ev, req)
require.NoError(t, err)
exb, err := io.ReadAll(eb())
require.NoError(t, err)
exs := string(exb[0 : len(exb)-2]) // remove trailing double newline
if topicsForOpsFeed[top] {
if err := opn.WaitForSubscription(ctx); err != nil {
t.Fatal(err)
}
// Send the event on the feed.
s.OperationNotifier.OperationFeed().Send(ev)
} else {
if err := stn.WaitForSubscription(ctx); err != nil {
t.Fatal(err)
}
// Send the event on the feed.
s.StateNotifier.StateFeed().Send(ev)
}
expected[exs] = true
}
done := make(chan struct{})
go func() {
defer close(done)
for {
ev, err := sseR.ReadEvent()
if err == io.EOF {
return
}
require.NoError(t, err)
str := string(ev)
delete(expected, str)
if len(expected) == 0 {
return
}
}
}()
select {
case <-done:
break
case <-ctx.Done():
t.Fatalf("context canceled / timed out waiting for events, err=%v", ctx.Err())
}
require.Equal(t, 0, len(expected), "expected events not seen")
}
func (f *flushableResponseRecorder) Flush() {
f.flushed = true
func (tr *topicRequest) testHttpRequest(_ *testing.T) *http.Request {
tq := make([]string, 0, len(tr.topics))
for topic := range tr.topics {
tq = append(tq, "topics="+topic)
}
return httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://example.com/eth/v1/events?%s", strings.Join(tq, "&")), nil)
}
func TestStreamEvents_OperationsEvents(t *testing.T) {
t.Run("operations", func(t *testing.T) {
s := &Server{
StateNotifier: &mockChain.MockStateNotifier{},
OperationNotifier: &mockChain.MockOperationNotifier{},
}
func operationEventsFixtures(t *testing.T) (*topicRequest, []*feed.Event) {
topics, err := newTopicRequest([]string{
AttestationTopic,
VoluntaryExitTopic,
SyncCommitteeContributionTopic,
BLSToExecutionChangeTopic,
BlobSidecarTopic,
AttesterSlashingTopic,
ProposerSlashingTopic,
})
require.NoError(t, err)
ro, err := blocks.NewROBlob(util.HydrateBlobSidecar(&eth.BlobSidecar{}))
require.NoError(t, err)
vblob := blocks.NewVerifiedROBlob(ro)
topics := []string{
AttestationTopic,
VoluntaryExitTopic,
SyncCommitteeContributionTopic,
BLSToExecutionChangeTopic,
BlobSidecarTopic,
AttesterSlashingTopic,
ProposerSlashingTopic,
}
for i, topic := range topics {
topics[i] = "topics=" + topic
}
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://example.com/eth/v1/events?%s", strings.Join(topics, "&")), nil)
w := &flushableResponseRecorder{
ResponseRecorder: httptest.NewRecorder(),
}
go func() {
s.StreamEvents(w, request)
}()
// wait for initiation of StreamEvents
time.Sleep(100 * time.Millisecond)
s.OperationNotifier.OperationFeed().Send(&feed.Event{
return topics, []*feed.Event{
&feed.Event{
Type: operation.UnaggregatedAttReceived,
Data: &operation.UnAggregatedAttReceivedData{
Attestation: util.HydrateAttestation(&eth.Attestation{}),
},
})
s.OperationNotifier.OperationFeed().Send(&feed.Event{
},
&feed.Event{
Type: operation.AggregatedAttReceived,
Data: &operation.AggregatedAttReceivedData{
Attestation: &eth.AggregateAttestationAndProof{
@@ -81,8 +125,8 @@ func TestStreamEvents_OperationsEvents(t *testing.T) {
SelectionProof: make([]byte, 96),
},
},
})
s.OperationNotifier.OperationFeed().Send(&feed.Event{
},
&feed.Event{
Type: operation.ExitReceived,
Data: &operation.ExitReceivedData{
Exit: &eth.SignedVoluntaryExit{
@@ -93,8 +137,8 @@ func TestStreamEvents_OperationsEvents(t *testing.T) {
Signature: make([]byte, 96),
},
},
})
s.OperationNotifier.OperationFeed().Send(&feed.Event{
},
&feed.Event{
Type: operation.SyncCommitteeContributionReceived,
Data: &operation.SyncCommitteeContributionReceivedData{
Contribution: &eth.SignedContributionAndProof{
@@ -112,8 +156,8 @@ func TestStreamEvents_OperationsEvents(t *testing.T) {
Signature: make([]byte, 96),
},
},
})
s.OperationNotifier.OperationFeed().Send(&feed.Event{
},
&feed.Event{
Type: operation.BLSToExecutionChangeReceived,
Data: &operation.BLSToExecutionChangeReceivedData{
Change: &eth.SignedBLSToExecutionChange{
@@ -125,18 +169,14 @@ func TestStreamEvents_OperationsEvents(t *testing.T) {
Signature: make([]byte, 96),
},
},
})
ro, err := blocks.NewROBlob(util.HydrateBlobSidecar(&eth.BlobSidecar{}))
require.NoError(t, err)
vblob := blocks.NewVerifiedROBlob(ro)
s.OperationNotifier.OperationFeed().Send(&feed.Event{
},
&feed.Event{
Type: operation.BlobSidecarReceived,
Data: &operation.BlobSidecarReceivedData{
Blob: &vblob,
},
})
s.OperationNotifier.OperationFeed().Send(&feed.Event{
},
&feed.Event{
Type: operation.AttesterSlashingReceived,
Data: &operation.AttesterSlashingReceivedData{
AttesterSlashing: &eth.AttesterSlashing{
@@ -168,9 +208,8 @@ func TestStreamEvents_OperationsEvents(t *testing.T) {
},
},
},
})
s.OperationNotifier.OperationFeed().Send(&feed.Event{
},
&feed.Event{
Type: operation.ProposerSlashingReceived,
Data: &operation.ProposerSlashingReceivedData{
ProposerSlashing: &eth.ProposerSlashing{
@@ -192,100 +231,107 @@ func TestStreamEvents_OperationsEvents(t *testing.T) {
},
},
},
})
},
}
}
time.Sleep(1 * time.Second)
request.Context().Done()
func TestStreamEvents_OperationsEvents(t *testing.T) {
t.Run("operations", func(t *testing.T) {
stn := mockChain.NewEventFeedWrapper()
opn := mockChain.NewEventFeedWrapper()
s := &Server{
StateNotifier: &mockChain.SimpleNotifier{Feed: stn},
OperationNotifier: &mockChain.SimpleNotifier{Feed: opn},
}
resp := w.Result()
body, err := io.ReadAll(resp.Body)
require.NoError(t, err)
require.NotNil(t, body)
assert.Equal(t, operationsResult, string(body))
topics, events := operationEventsFixtures(t)
request := topics.testHttpRequest(t)
w := NewStreamingResponseWriterRecorder()
go func() {
s.StreamEvents(w, request)
}()
requireAllEventsReceived(t, stn, opn, events, topics, s, w)
})
t.Run("state", func(t *testing.T) {
stn := mockChain.NewEventFeedWrapper()
opn := mockChain.NewEventFeedWrapper()
s := &Server{
StateNotifier: &mockChain.MockStateNotifier{},
OperationNotifier: &mockChain.MockOperationNotifier{},
StateNotifier: &mockChain.SimpleNotifier{Feed: stn},
OperationNotifier: &mockChain.SimpleNotifier{Feed: opn},
}
topics := []string{HeadTopic, FinalizedCheckpointTopic, ChainReorgTopic, BlockTopic}
for i, topic := range topics {
topics[i] = "topics=" + topic
}
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://example.com/eth/v1/events?%s", strings.Join(topics, "&")), nil)
w := &flushableResponseRecorder{
ResponseRecorder: httptest.NewRecorder(),
topics, err := newTopicRequest([]string{
HeadTopic,
FinalizedCheckpointTopic,
ChainReorgTopic,
BlockTopic,
})
require.NoError(t, err)
request := topics.testHttpRequest(t)
w := NewStreamingResponseWriterRecorder()
b, err := blocks.NewSignedBeaconBlock(util.HydrateSignedBeaconBlock(&eth.SignedBeaconBlock{}))
require.NoError(t, err)
events := []*feed.Event{
&feed.Event{
Type: statefeed.BlockProcessed,
Data: &statefeed.BlockProcessedData{
Slot: 0,
BlockRoot: [32]byte{},
SignedBlock: b,
Verified: true,
Optimistic: false,
},
},
&feed.Event{
Type: statefeed.NewHead,
Data: &ethpb.EventHead{
Slot: 0,
Block: make([]byte, 32),
State: make([]byte, 32),
EpochTransition: true,
PreviousDutyDependentRoot: make([]byte, 32),
CurrentDutyDependentRoot: make([]byte, 32),
ExecutionOptimistic: false,
},
},
&feed.Event{
Type: statefeed.Reorg,
Data: &ethpb.EventChainReorg{
Slot: 0,
Depth: 0,
OldHeadBlock: make([]byte, 32),
NewHeadBlock: make([]byte, 32),
OldHeadState: make([]byte, 32),
NewHeadState: make([]byte, 32),
Epoch: 0,
ExecutionOptimistic: false,
},
},
&feed.Event{
Type: statefeed.FinalizedCheckpoint,
Data: &ethpb.EventFinalizedCheckpoint{
Block: make([]byte, 32),
State: make([]byte, 32),
Epoch: 0,
ExecutionOptimistic: false,
},
},
}
go func() {
s.StreamEvents(w, request)
}()
// wait for initiation of StreamEvents
time.Sleep(100 * time.Millisecond)
s.StateNotifier.StateFeed().Send(&feed.Event{
Type: statefeed.NewHead,
Data: &ethpb.EventHead{
Slot: 0,
Block: make([]byte, 32),
State: make([]byte, 32),
EpochTransition: true,
PreviousDutyDependentRoot: make([]byte, 32),
CurrentDutyDependentRoot: make([]byte, 32),
ExecutionOptimistic: false,
},
})
s.StateNotifier.StateFeed().Send(&feed.Event{
Type: statefeed.FinalizedCheckpoint,
Data: &ethpb.EventFinalizedCheckpoint{
Block: make([]byte, 32),
State: make([]byte, 32),
Epoch: 0,
ExecutionOptimistic: false,
},
})
s.StateNotifier.StateFeed().Send(&feed.Event{
Type: statefeed.Reorg,
Data: &ethpb.EventChainReorg{
Slot: 0,
Depth: 0,
OldHeadBlock: make([]byte, 32),
NewHeadBlock: make([]byte, 32),
OldHeadState: make([]byte, 32),
NewHeadState: make([]byte, 32),
Epoch: 0,
ExecutionOptimistic: false,
},
})
b, err := blocks.NewSignedBeaconBlock(util.HydrateSignedBeaconBlock(&eth.SignedBeaconBlock{}))
require.NoError(t, err)
s.StateNotifier.StateFeed().Send(&feed.Event{
Type: statefeed.BlockProcessed,
Data: &statefeed.BlockProcessedData{
Slot: 0,
BlockRoot: [32]byte{},
SignedBlock: b,
Verified: true,
Optimistic: false,
},
})
// wait for feed
time.Sleep(1 * time.Second)
request.Context().Done()
resp := w.Result()
body, err := io.ReadAll(resp.Body)
require.NoError(t, err)
require.NotNil(t, body)
assert.Equal(t, stateResult, string(body))
requireAllEventsReceived(t, stn, opn, events, topics, s, w)
})
t.Run("payload attributes", func(t *testing.T) {
type testCase struct {
name string
getState func() state.BeaconState
getBlock func() interfaces.SignedBeaconBlock
expected string
SetTrackedValidatorsCache func(*cache.TrackedValidatorsCache)
}
testCases := []testCase{
@@ -301,7 +347,6 @@ func TestStreamEvents_OperationsEvents(t *testing.T) {
require.NoError(t, err)
return b
},
expected: payloadAttributesBellatrixResult,
},
{
name: "capella",
@@ -315,7 +360,6 @@ func TestStreamEvents_OperationsEvents(t *testing.T) {
require.NoError(t, err)
return b
},
expected: payloadAttributesCapellaResult,
},
{
name: "deneb",
@@ -329,7 +373,6 @@ func TestStreamEvents_OperationsEvents(t *testing.T) {
require.NoError(t, err)
return b
},
expected: payloadAttributesDenebResult,
},
{
name: "electra",
@@ -343,7 +386,6 @@ func TestStreamEvents_OperationsEvents(t *testing.T) {
require.NoError(t, err)
return b
},
expected: payloadAttributesElectraResultWithTVC,
SetTrackedValidatorsCache: func(c *cache.TrackedValidatorsCache) {
c.Set(cache.TrackedValidator{
Active: true,
@@ -368,9 +410,11 @@ func TestStreamEvents_OperationsEvents(t *testing.T) {
Slot: &currentSlot,
}
stn := mockChain.NewEventFeedWrapper()
opn := mockChain.NewEventFeedWrapper()
s := &Server{
StateNotifier: &mockChain.MockStateNotifier{},
OperationNotifier: &mockChain.MockOperationNotifier{},
StateNotifier: &mockChain.SimpleNotifier{Feed: stn},
OperationNotifier: &mockChain.SimpleNotifier{Feed: opn},
HeadFetcher: mockChainService,
ChainInfoFetcher: mockChainService,
TrackedValidatorsCache: cache.NewTrackedValidatorsCache(),
@@ -378,100 +422,76 @@ func TestStreamEvents_OperationsEvents(t *testing.T) {
if tc.SetTrackedValidatorsCache != nil {
tc.SetTrackedValidatorsCache(s.TrackedValidatorsCache)
}
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://example.com/eth/v1/events?topics=%s", PayloadAttributesTopic), nil)
w := &flushableResponseRecorder{
ResponseRecorder: httptest.NewRecorder(),
}
topics, err := newTopicRequest([]string{PayloadAttributesTopic})
require.NoError(t, err)
request := topics.testHttpRequest(t)
w := NewStreamingResponseWriterRecorder()
events := []*feed.Event{&feed.Event{Type: statefeed.MissedSlot}}
go func() {
s.StreamEvents(w, request)
}()
// wait for initiation of StreamEvents
time.Sleep(100 * time.Millisecond)
s.StateNotifier.StateFeed().Send(&feed.Event{Type: statefeed.MissedSlot})
// wait for feed
time.Sleep(1 * time.Second)
request.Context().Done()
resp := w.Result()
body, err := io.ReadAll(resp.Body)
require.NoError(t, err)
require.NotNil(t, body)
assert.Equal(t, tc.expected, string(body), "wrong result for "+tc.name)
requireAllEventsReceived(t, stn, opn, events, topics, s, w)
}
})
}
const operationsResult = `:
func TestStuckReader(t *testing.T) {
topics, events := operationEventsFixtures(t)
require.Equal(t, 8, len(events))
// set eventFeedDepth to a number lower than the events we intend to send to force the server to drop the reader.
stn := mockChain.NewEventFeedWrapper()
opn := mockChain.NewEventFeedWrapper()
s := &Server{
StateNotifier: &mockChain.SimpleNotifier{Feed: stn},
OperationNotifier: &mockChain.SimpleNotifier{Feed: opn},
EventFeedDepth: len(events) - 1,
}
event: attestation
data: {"aggregation_bits":"0x00","data":{"slot":"0","index":"0","beacon_block_root":"0x0000000000000000000000000000000000000000000000000000000000000000","source":{"epoch":"0","root":"0x0000000000000000000000000000000000000000000000000000000000000000"},"target":{"epoch":"0","root":"0x0000000000000000000000000000000000000000000000000000000000000000"}},"signature":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
eventsWritten := make(chan struct{})
go func() {
for i := range events {
ev := events[i]
top := topicForEvent(ev)
if topicsForOpsFeed[top] {
err := opn.WaitForSubscription(ctx)
require.NoError(t, err)
s.OperationNotifier.OperationFeed().Send(ev)
} else {
err := stn.WaitForSubscription(ctx)
require.NoError(t, err)
s.StateNotifier.StateFeed().Send(ev)
}
}
close(eventsWritten)
}()
event: attestation
data: {"aggregation_bits":"0x00","data":{"slot":"0","index":"0","beacon_block_root":"0x0000000000000000000000000000000000000000000000000000000000000000","source":{"epoch":"0","root":"0x0000000000000000000000000000000000000000000000000000000000000000"},"target":{"epoch":"0","root":"0x0000000000000000000000000000000000000000000000000000000000000000"}},"signature":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}
request := topics.testHttpRequest(t)
w := NewStreamingResponseWriterRecorder()
event: voluntary_exit
data: {"message":{"epoch":"0","validator_index":"0"},"signature":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}
handlerFinished := make(chan struct{})
go func() {
s.StreamEvents(w, request)
close(handlerFinished)
}()
event: contribution_and_proof
data: {"message":{"aggregator_index":"0","contribution":{"slot":"0","beacon_block_root":"0x0000000000000000000000000000000000000000000000000000000000000000","subcommittee_index":"0","aggregation_bits":"0x00000000000000000000000000000000","signature":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"selection_proof":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"signature":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}
// Make sure that the stream writer shut down when the reader failed to clear the write buffer.
select {
case <-handlerFinished:
// We expect the stream handler to max out the queue buffer and exit gracefully.
return
case <-ctx.Done():
t.Fatalf("context canceled / timed out waiting for handler completion, err=%v", ctx.Err())
}
event: bls_to_execution_change
data: {"message":{"validator_index":"0","from_bls_pubkey":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","to_execution_address":"0x0000000000000000000000000000000000000000"},"signature":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}
event: blob_sidecar
data: {"block_root":"0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c","index":"0","slot":"0","kzg_commitment":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","versioned_hash":"0x01b0761f87b081d5cf10757ccc89f12be355c70e2e29df288b65b30710dcbcd1"}
event: attester_slashing
data: {"attestation_1":{"attesting_indices":["0","1"],"data":{"slot":"0","index":"0","beacon_block_root":"0x0000000000000000000000000000000000000000000000000000000000000000","source":{"epoch":"0","root":"0x0000000000000000000000000000000000000000000000000000000000000000"},"target":{"epoch":"0","root":"0x0000000000000000000000000000000000000000000000000000000000000000"}},"signature":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"attestation_2":{"attesting_indices":["0","1"],"data":{"slot":"0","index":"0","beacon_block_root":"0x0000000000000000000000000000000000000000000000000000000000000000","source":{"epoch":"0","root":"0x0000000000000000000000000000000000000000000000000000000000000000"},"target":{"epoch":"0","root":"0x0000000000000000000000000000000000000000000000000000000000000000"}},"signature":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
event: proposer_slashing
data: {"signed_header_1":{"message":{"slot":"0","proposer_index":"0","parent_root":"0x0000000000000000000000000000000000000000000000000000000000000000","state_root":"0x0000000000000000000000000000000000000000000000000000000000000000","body_root":"0x0000000000000000000000000000000000000000000000000000000000000000"},"signature":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"signed_header_2":{"message":{"slot":"0","proposer_index":"0","parent_root":"0x0000000000000000000000000000000000000000000000000000000000000000","state_root":"0x0000000000000000000000000000000000000000000000000000000000000000","body_root":"0x0000000000000000000000000000000000000000000000000000000000000000"},"signature":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}
`
const stateResult = `:
event: head
data: {"slot":"0","block":"0x0000000000000000000000000000000000000000000000000000000000000000","state":"0x0000000000000000000000000000000000000000000000000000000000000000","epoch_transition":true,"execution_optimistic":false,"previous_duty_dependent_root":"0x0000000000000000000000000000000000000000000000000000000000000000","current_duty_dependent_root":"0x0000000000000000000000000000000000000000000000000000000000000000"}
event: finalized_checkpoint
data: {"block":"0x0000000000000000000000000000000000000000000000000000000000000000","state":"0x0000000000000000000000000000000000000000000000000000000000000000","epoch":"0","execution_optimistic":false}
event: chain_reorg
data: {"slot":"0","depth":"0","old_head_block":"0x0000000000000000000000000000000000000000000000000000000000000000","old_head_state":"0x0000000000000000000000000000000000000000000000000000000000000000","new_head_block":"0x0000000000000000000000000000000000000000000000000000000000000000","new_head_state":"0x0000000000000000000000000000000000000000000000000000000000000000","epoch":"0","execution_optimistic":false}
event: block
data: {"slot":"0","block":"0xeade62f0457b2fdf48e7d3fc4b60736688286be7c7a3ac4c9a16a5e0600bd9e4","execution_optimistic":false}
`
const payloadAttributesBellatrixResult = `:
event: payload_attributes
data: {"version":"bellatrix","data":{"proposer_index":"0","proposal_slot":"1","parent_block_number":"0","parent_block_root":"0x0000000000000000000000000000000000000000000000000000000000000000","parent_block_hash":"0x0000000000000000000000000000000000000000000000000000000000000000","payload_attributes":{"timestamp":"12","prev_randao":"0x0000000000000000000000000000000000000000000000000000000000000000","suggested_fee_recipient":"0x0000000000000000000000000000000000000000"}}}
`
const payloadAttributesCapellaResult = `:
event: payload_attributes
data: {"version":"capella","data":{"proposer_index":"0","proposal_slot":"1","parent_block_number":"0","parent_block_root":"0x0000000000000000000000000000000000000000000000000000000000000000","parent_block_hash":"0x0000000000000000000000000000000000000000000000000000000000000000","payload_attributes":{"timestamp":"12","prev_randao":"0x0000000000000000000000000000000000000000000000000000000000000000","suggested_fee_recipient":"0x0000000000000000000000000000000000000000","withdrawals":[]}}}
`
const payloadAttributesDenebResult = `:
event: payload_attributes
data: {"version":"deneb","data":{"proposer_index":"0","proposal_slot":"1","parent_block_number":"0","parent_block_root":"0x0000000000000000000000000000000000000000000000000000000000000000","parent_block_hash":"0x0000000000000000000000000000000000000000000000000000000000000000","payload_attributes":{"timestamp":"12","prev_randao":"0x0000000000000000000000000000000000000000000000000000000000000000","suggested_fee_recipient":"0x0000000000000000000000000000000000000000","withdrawals":[],"parent_beacon_block_root":"0xbef96cb938fd48b2403d3e662664325abb0102ed12737cbb80d717520e50cf4a"}}}
`
const payloadAttributesElectraResultWithTVC = `:
event: payload_attributes
data: {"version":"electra","data":{"proposer_index":"0","proposal_slot":"1","parent_block_number":"0","parent_block_root":"0x0000000000000000000000000000000000000000000000000000000000000000","parent_block_hash":"0x0000000000000000000000000000000000000000000000000000000000000000","payload_attributes":{"timestamp":"12","prev_randao":"0x0000000000000000000000000000000000000000000000000000000000000000","suggested_fee_recipient":"0xd2dbd02e4efe087d7d195de828b9dd25f19a89c9","withdrawals":[],"parent_beacon_block_root":"0xf2110e448638f41cb34514ecdbb49c055536cd5f715f1cb259d1287bb900853e"}}}
`
// Also make sure all the events were written.
select {
case <-eventsWritten:
// We expect the stream handler to max out the queue buffer and exit gracefully.
return
case <-ctx.Done():
t.Fatalf("context canceled / timed out waiting to write all events, err=%v", ctx.Err())
}
}

View File

@@ -0,0 +1,75 @@
package events
import (
"io"
"net/http"
"net/http/httptest"
"testing"
"github.com/prysmaticlabs/prysm/v5/testing/require"
)
type StreamingResponseWriterRecorder struct {
http.ResponseWriter
r io.Reader
w io.Writer
statusWritten *int
status chan int
bodyRecording []byte
flushed bool
}
func (w *StreamingResponseWriterRecorder) StatusChan() chan int {
return w.status
}
func NewStreamingResponseWriterRecorder() *StreamingResponseWriterRecorder {
r, w := io.Pipe()
return &StreamingResponseWriterRecorder{
ResponseWriter: httptest.NewRecorder(),
r: r,
w: w,
status: make(chan int, 1),
}
}
// Write implements http.ResponseWriter.
func (w *StreamingResponseWriterRecorder) Write(data []byte) (int, error) {
w.WriteHeader(http.StatusOK)
n, err := w.w.Write(data)
if err != nil {
return n, err
}
return w.ResponseWriter.Write(data)
}
// WriteHeader implements http.ResponseWriter.
func (w *StreamingResponseWriterRecorder) WriteHeader(statusCode int) {
if w.statusWritten != nil {
return
}
w.statusWritten = &statusCode
w.status <- statusCode
w.ResponseWriter.WriteHeader(statusCode)
}
func (w *StreamingResponseWriterRecorder) Body() io.Reader {
return w.r
}
func (w *StreamingResponseWriterRecorder) RequireStatus(t *testing.T, status int) {
if w.statusWritten == nil {
t.Fatal("WriteHeader was not called")
}
require.Equal(t, status, *w.statusWritten)
}
func (w *StreamingResponseWriterRecorder) Flush() {
fw, ok := w.ResponseWriter.(http.Flusher)
if ok {
fw.Flush()
}
w.flushed = true
}
var _ http.ResponseWriter = &StreamingResponseWriterRecorder{}

View File

@@ -4,6 +4,8 @@
package events
import (
"time"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/blockchain"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/cache"
opfeed "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/feed/operation"
@@ -18,4 +20,6 @@ type Server struct {
HeadFetcher blockchain.HeadFetcher
ChainInfoFetcher blockchain.ChainInfoFetcher
TrackedValidatorsCache *cache.TrackedValidatorsCache
KeepAliveInterval time.Duration
EventFeedDepth int
}

View File

@@ -20,14 +20,12 @@ go_library(
"//beacon-chain/state:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//consensus-types:go_default_library",
"//consensus-types/blocks:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//consensus-types/primitives:go_default_library",
"//encoding/ssz:go_default_library",
"//monitoring/tracing/trace:go_default_library",
"//network/httputil:go_default_library",
"//proto/eth/v2:go_default_library",
"//proto/migration:go_default_library",
"//runtime/version:go_default_library",
"//time/slots:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
@@ -55,7 +53,6 @@ go_test(
"//consensus-types/blocks:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//consensus-types/primitives:go_default_library",
"//encoding/bytesutil:go_default_library",
"//proto/eth/v1:go_default_library",
"//proto/eth/v2:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",

View File

@@ -47,7 +47,7 @@ func (s *Server) GetLightClientBootstrap(w http.ResponseWriter, req *http.Reques
return
}
bootstrap, err := createLightClientBootstrap(ctx, state, blk.Block())
bootstrap, err := createLightClientBootstrap(ctx, state, blk)
if err != nil {
httputil.HandleError(w, "could not get light client bootstrap: "+err.Error(), http.StatusInternalServerError)
return
@@ -204,6 +204,7 @@ func (s *Server) GetLightClientUpdatesByRange(w http.ResponseWriter, req *http.R
state,
block,
attestedState,
attestedBlock,
finalizedBlock,
)
@@ -267,7 +268,7 @@ func (s *Server) GetLightClientFinalityUpdate(w http.ResponseWriter, req *http.R
return
}
update, err := newLightClientFinalityUpdateFromBeaconState(ctx, st, block, attestedState, finalizedBlock)
update, err := newLightClientFinalityUpdateFromBeaconState(ctx, st, block, attestedState, attestedBlock, finalizedBlock)
if err != nil {
httputil.HandleError(w, "Could not get light client finality update: "+err.Error(), http.StatusInternalServerError)
return
@@ -312,7 +313,7 @@ func (s *Server) GetLightClientOptimisticUpdate(w http.ResponseWriter, req *http
return
}
update, err := newLightClientOptimisticUpdateFromBeaconState(ctx, st, block, attestedState)
update, err := newLightClientOptimisticUpdateFromBeaconState(ctx, st, block, attestedState, attestedBlock)
if err != nil {
httputil.HandleError(w, "Could not get light client optimistic update: "+err.Error(), http.StatusInternalServerError)
return

View File

@@ -7,6 +7,7 @@ import (
"fmt"
"net/http"
"net/http/httptest"
"strconv"
"testing"
"github.com/ethereum/go-ethereum/common/hexutil"
@@ -19,49 +20,29 @@ import (
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/testing/require"
"github.com/prysmaticlabs/prysm/v5/testing/util"
)
func TestLightClientHandler_GetLightClientBootstrap_Altair(t *testing.T) {
helpers.ClearCache()
slot := primitives.Slot(params.BeaconConfig().AltairForkEpoch * primitives.Epoch(params.BeaconConfig().SlotsPerEpoch)).Add(1)
l := util.NewTestLightClient(t).SetupTestAltair()
b := util.NewBeaconBlockAltair()
b.Block.StateRoot = bytesutil.PadTo([]byte("foo"), 32)
b.Block.Slot = slot
signedBlock, err := blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
header, err := signedBlock.Header()
slot := l.State.Slot()
stateRoot, err := l.State.HashTreeRoot(l.Ctx)
require.NoError(t, err)
r, err := b.Block.HashTreeRoot()
require.NoError(t, err)
bs, err := util.NewBeaconStateAltair(func(state *ethpb.BeaconStateAltair) error {
state.BlockRoots[0] = r[:]
return nil
})
require.NoError(t, err)
require.NoError(t, bs.SetSlot(slot))
require.NoError(t, bs.SetLatestBlockHeader(header.Header))
mockBlocker := &testutil.MockBlocker{BlockToReturn: signedBlock}
mockBlocker := &testutil.MockBlocker{BlockToReturn: l.Block}
mockChainService := &mock.ChainService{Optimistic: true, Slot: &slot}
s := &Server{
Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{
slot: bs,
slot: l.State,
}},
Blocker: mockBlocker,
HeadFetcher: mockChainService,
}
request := httptest.NewRequest("GET", "http://foo.com/", nil)
request.SetPathValue("block_root", hexutil.Encode(r[:]))
request.SetPathValue("block_root", hexutil.Encode(stateRoot[:]))
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
@@ -74,47 +55,35 @@ func TestLightClientHandler_GetLightClientBootstrap_Altair(t *testing.T) {
err = json.Unmarshal(resp.Data.Header, &respHeader)
require.NoError(t, err)
require.Equal(t, "altair", resp.Version)
require.Equal(t, hexutil.Encode(header.Header.BodyRoot), respHeader.Beacon.BodyRoot)
require.NotNil(t, resp.Data)
blockHeader, err := l.Block.Header()
require.NoError(t, err)
require.Equal(t, hexutil.Encode(blockHeader.Header.BodyRoot), respHeader.Beacon.BodyRoot)
require.Equal(t, strconv.FormatUint(uint64(blockHeader.Header.Slot), 10), respHeader.Beacon.Slot)
require.NotNil(t, resp.Data.CurrentSyncCommittee)
require.NotNil(t, resp.Data.CurrentSyncCommitteeBranch)
}
func TestLightClientHandler_GetLightClientBootstrap_Capella(t *testing.T) {
helpers.ClearCache()
slot := primitives.Slot(params.BeaconConfig().CapellaForkEpoch * primitives.Epoch(params.BeaconConfig().SlotsPerEpoch)).Add(1)
l := util.NewTestLightClient(t).SetupTestCapella(false) // result is same for true and false
b := util.NewBeaconBlockCapella()
b.Block.StateRoot = bytesutil.PadTo([]byte("foo"), 32)
b.Block.Slot = slot
signedBlock, err := blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
header, err := signedBlock.Header()
slot := l.State.Slot()
stateRoot, err := l.State.HashTreeRoot(l.Ctx)
require.NoError(t, err)
r, err := b.Block.HashTreeRoot()
require.NoError(t, err)
bs, err := util.NewBeaconStateCapella(func(state *ethpb.BeaconStateCapella) error {
state.BlockRoots[0] = r[:]
return nil
})
require.NoError(t, err)
require.NoError(t, bs.SetSlot(slot))
require.NoError(t, bs.SetLatestBlockHeader(header.Header))
mockBlocker := &testutil.MockBlocker{BlockToReturn: signedBlock}
mockBlocker := &testutil.MockBlocker{BlockToReturn: l.Block}
mockChainService := &mock.ChainService{Optimistic: true, Slot: &slot}
s := &Server{
Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{
slot: bs,
slot: l.State,
}},
Blocker: mockBlocker,
HeadFetcher: mockChainService,
}
request := httptest.NewRequest("GET", "http://foo.com/", nil)
request.SetPathValue("block_root", hexutil.Encode(r[:]))
request.SetPathValue("block_root", hexutil.Encode(stateRoot[:]))
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
@@ -123,51 +92,38 @@ func TestLightClientHandler_GetLightClientBootstrap_Capella(t *testing.T) {
var resp structs.LightClientBootstrapResponse
err = json.Unmarshal(writer.Body.Bytes(), &resp)
require.NoError(t, err)
var respHeader structs.LightClientHeaderCapella
var respHeader structs.LightClientHeader
err = json.Unmarshal(resp.Data.Header, &respHeader)
require.NoError(t, err)
require.Equal(t, "capella", resp.Version)
require.Equal(t, hexutil.Encode(header.Header.BodyRoot), respHeader.Beacon.BodyRoot)
require.NotNil(t, resp.Data)
blockHeader, err := l.Block.Header()
require.NoError(t, err)
require.Equal(t, hexutil.Encode(blockHeader.Header.BodyRoot), respHeader.Beacon.BodyRoot)
require.Equal(t, strconv.FormatUint(uint64(blockHeader.Header.Slot), 10), respHeader.Beacon.Slot)
require.NotNil(t, resp.Data.CurrentSyncCommittee)
require.NotNil(t, resp.Data.CurrentSyncCommitteeBranch)
}
func TestLightClientHandler_GetLightClientBootstrap_Deneb(t *testing.T) {
helpers.ClearCache()
slot := primitives.Slot(params.BeaconConfig().DenebForkEpoch * primitives.Epoch(params.BeaconConfig().SlotsPerEpoch)).Add(1)
l := util.NewTestLightClient(t).SetupTestDeneb(false) // result is same for true and false
b := util.NewBeaconBlockDeneb()
b.Block.StateRoot = bytesutil.PadTo([]byte("foo"), 32)
b.Block.Slot = slot
signedBlock, err := blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
header, err := signedBlock.Header()
slot := l.State.Slot()
stateRoot, err := l.State.HashTreeRoot(l.Ctx)
require.NoError(t, err)
r, err := b.Block.HashTreeRoot()
require.NoError(t, err)
bs, err := util.NewBeaconStateDeneb(func(state *ethpb.BeaconStateDeneb) error {
state.BlockRoots[0] = r[:]
return nil
})
require.NoError(t, err)
require.NoError(t, bs.SetSlot(slot))
require.NoError(t, bs.SetLatestBlockHeader(header.Header))
mockBlocker := &testutil.MockBlocker{BlockToReturn: signedBlock}
mockBlocker := &testutil.MockBlocker{BlockToReturn: l.Block}
mockChainService := &mock.ChainService{Optimistic: true, Slot: &slot}
s := &Server{
Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{
slot: bs,
slot: l.State,
}},
Blocker: mockBlocker,
HeadFetcher: mockChainService,
}
request := httptest.NewRequest("GET", "http://foo.com/", nil)
request.SetPathValue("block_root", hexutil.Encode(r[:]))
request.SetPathValue("block_root", hexutil.Encode(stateRoot[:]))
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
@@ -176,12 +132,58 @@ func TestLightClientHandler_GetLightClientBootstrap_Deneb(t *testing.T) {
var resp structs.LightClientBootstrapResponse
err = json.Unmarshal(writer.Body.Bytes(), &resp)
require.NoError(t, err)
var respHeader structs.LightClientHeaderDeneb
var respHeader structs.LightClientHeader
err = json.Unmarshal(resp.Data.Header, &respHeader)
require.NoError(t, err)
require.Equal(t, "deneb", resp.Version)
require.Equal(t, hexutil.Encode(header.Header.BodyRoot), respHeader.Beacon.BodyRoot)
require.NotNil(t, resp.Data)
blockHeader, err := l.Block.Header()
require.NoError(t, err)
require.Equal(t, hexutil.Encode(blockHeader.Header.BodyRoot), respHeader.Beacon.BodyRoot)
require.Equal(t, strconv.FormatUint(uint64(blockHeader.Header.Slot), 10), respHeader.Beacon.Slot)
require.NotNil(t, resp.Data.CurrentSyncCommittee)
require.NotNil(t, resp.Data.CurrentSyncCommitteeBranch)
}
func TestLightClientHandler_GetLightClientBootstrap_Electra(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestElectra(false) // result is same for true and false
slot := l.State.Slot()
stateRoot, err := l.State.HashTreeRoot(l.Ctx)
require.NoError(t, err)
mockBlocker := &testutil.MockBlocker{BlockToReturn: l.Block}
mockChainService := &mock.ChainService{Optimistic: true, Slot: &slot}
s := &Server{
Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{
slot: l.State,
}},
Blocker: mockBlocker,
HeadFetcher: mockChainService,
}
request := httptest.NewRequest("GET", "http://foo.com/", nil)
request.SetPathValue("block_root", hexutil.Encode(stateRoot[:]))
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.GetLightClientBootstrap(writer, request)
require.Equal(t, http.StatusOK, writer.Code)
var resp structs.LightClientBootstrapResponse
err = json.Unmarshal(writer.Body.Bytes(), &resp)
require.NoError(t, err)
var respHeader structs.LightClientHeader
err = json.Unmarshal(resp.Data.Header, &respHeader)
require.NoError(t, err)
require.Equal(t, "electra", resp.Version)
blockHeader, err := l.Block.Header()
require.NoError(t, err)
require.Equal(t, hexutil.Encode(blockHeader.Header.BodyRoot), respHeader.Beacon.BodyRoot)
require.Equal(t, strconv.FormatUint(uint64(blockHeader.Header.Slot), 10), respHeader.Beacon.Slot)
require.NotNil(t, resp.Data.CurrentSyncCommittee)
require.NotNil(t, resp.Data.CurrentSyncCommitteeBranch)
}
func TestLightClientHandler_GetLightClientUpdatesByRangeAltair(t *testing.T) {

View File

@@ -7,10 +7,9 @@ import (
"reflect"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v5/proto/migration"
lightclient "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/light-client"
consensus_types "github.com/prysmaticlabs/prysm/v5/consensus-types"
"github.com/prysmaticlabs/prysm/v5/encoding/ssz"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/ethereum/go-ethereum/common/hexutil"
@@ -18,18 +17,17 @@ import (
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
v2 "github.com/prysmaticlabs/prysm/v5/proto/eth/v2"
"github.com/prysmaticlabs/prysm/v5/time/slots"
)
func createLightClientBootstrap(ctx context.Context, state state.BeaconState, blk interfaces.ReadOnlyBeaconBlock) (*structs.LightClientBootstrap, error) {
func createLightClientBootstrap(ctx context.Context, state state.BeaconState, blk interfaces.ReadOnlySignedBeaconBlock) (*structs.LightClientBootstrap, error) {
switch blk.Version() {
case version.Phase0:
return nil, fmt.Errorf("light client bootstrap is not supported for phase0")
case version.Altair, version.Bellatrix:
return createLightClientBootstrapAltair(ctx, state)
return createLightClientBootstrapAltair(ctx, state, blk)
case version.Capella:
return createLightClientBootstrapCapella(ctx, state, blk)
case version.Deneb, version.Electra:
@@ -38,24 +36,7 @@ func createLightClientBootstrap(ctx context.Context, state state.BeaconState, bl
return nil, fmt.Errorf("unsupported block version %s", version.String(blk.Version()))
}
// createLightClientBootstrapAltair - implements https://github.com/ethereum/consensus-specs/blob/3d235740e5f1e641d3b160c8688f26e7dc5a1894/specs/altair/light-client/full-node.md#create_light_client_bootstrap
// def create_light_client_bootstrap(state: BeaconState) -> LightClientBootstrap:
//
// assert compute_epoch_at_slot(state.slot) >= ALTAIR_FORK_EPOCH
// assert state.slot == state.latest_block_header.slot
//
// return LightClientBootstrap(
// header=BeaconBlockHeader(
// slot=state.latest_block_header.slot,
// proposer_index=state.latest_block_header.proposer_index,
// parent_root=state.latest_block_header.parent_root,
// state_root=hash_tree_root(state),
// body_root=state.latest_block_header.body_root,
// ),
// current_sync_committee=state.current_sync_committee,
// current_sync_committee_branch=compute_merkle_proof_for_state(state, CURRENT_SYNC_COMMITTEE_INDEX)
// )
func createLightClientBootstrapAltair(ctx context.Context, state state.BeaconState) (*structs.LightClientBootstrap, error) {
func createLightClientBootstrapAltair(ctx context.Context, state state.BeaconState, block interfaces.ReadOnlySignedBeaconBlock) (*structs.LightClientBootstrap, error) {
// assert compute_epoch_at_slot(state.slot) >= ALTAIR_FORK_EPOCH
if slots.ToEpoch(state.Slot()) < params.BeaconConfig().AltairForkEpoch {
return nil, fmt.Errorf("light client bootstrap is not supported before Altair, invalid slot %d", state.Slot())
@@ -67,55 +48,63 @@ func createLightClientBootstrapAltair(ctx context.Context, state state.BeaconSta
return nil, fmt.Errorf("state slot %d not equal to latest block header slot %d", state.Slot(), latestBlockHeader.Slot)
}
// Prepare data
// header.state_root = hash_tree_root(state)
stateRoot, err := state.HashTreeRoot(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not get state root")
}
latestBlockHeader.StateRoot = stateRoot[:]
// assert hash_tree_root(header) == hash_tree_root(block.message)
latestBlockHeaderRoot, err := latestBlockHeader.HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "could not get latest block header root")
}
beaconBlockRoot, err := block.Block().HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "could not get block root")
}
if latestBlockHeaderRoot != beaconBlockRoot {
return nil, fmt.Errorf("latest block header root %#x not equal to block root %#x", latestBlockHeaderRoot, beaconBlockRoot)
}
lightClientHeaderContainer, err := lightclient.BlockToLightClientHeader(block)
if err != nil {
return nil, errors.Wrap(err, "could not convert block to light client header")
}
lightClientHeader := lightClientHeaderContainer.GetHeaderAltair()
apiLightClientHeader := &structs.LightClientHeader{
Beacon: structs.BeaconBlockHeaderFromConsensus(migration.V1HeaderToV1Alpha1(lightClientHeader.Beacon)),
}
headerJSON, err := json.Marshal(apiLightClientHeader)
if err != nil {
return nil, errors.Wrap(err, "could not convert header to raw message")
}
currentSyncCommittee, err := state.CurrentSyncCommittee()
if err != nil {
return nil, errors.Wrap(err, "could not get current sync committee")
}
committee := structs.SyncCommitteeFromConsensus(currentSyncCommittee)
currentSyncCommitteeProof, err := state.CurrentSyncCommitteeProof(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not get current sync committee proof")
}
branch := make([]string, fieldparams.NextSyncCommitteeBranchDepth)
branch := make([]string, fieldparams.SyncCommitteeBranchDepth)
for i, proof := range currentSyncCommitteeProof {
branch[i] = hexutil.Encode(proof)
}
beacon := structs.BeaconBlockHeaderFromConsensus(latestBlockHeader)
if beacon == nil {
return nil, fmt.Errorf("could not get beacon block header")
}
header := &structs.LightClientHeader{
Beacon: beacon,
}
// Above shared util function won't calculate state root, so we need to do it manually
stateRoot, err := state.HashTreeRoot(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not get state root")
}
header.Beacon.StateRoot = hexutil.Encode(stateRoot[:])
headerJson, err := json.Marshal(header)
if err != nil {
return nil, errors.Wrap(err, "could not convert header to raw message")
}
// Return result
result := &structs.LightClientBootstrap{
Header: headerJson,
CurrentSyncCommittee: committee,
Header: headerJSON,
CurrentSyncCommittee: structs.SyncCommitteeFromConsensus(currentSyncCommittee),
CurrentSyncCommitteeBranch: branch,
}
return result, nil
}
func createLightClientBootstrapCapella(ctx context.Context, state state.BeaconState, block interfaces.ReadOnlyBeaconBlock) (*structs.LightClientBootstrap, error) {
func createLightClientBootstrapCapella(ctx context.Context, state state.BeaconState, block interfaces.ReadOnlySignedBeaconBlock) (*structs.LightClientBootstrap, error) {
// assert compute_epoch_at_slot(state.slot) >= CAPELLA_FORK_EPOCH
if slots.ToEpoch(state.Slot()) < params.BeaconConfig().CapellaForkEpoch {
return nil, fmt.Errorf("creating Capella light client bootstrap is not supported before Capella, invalid slot %d", state.Slot())
@@ -127,111 +116,63 @@ func createLightClientBootstrapCapella(ctx context.Context, state state.BeaconSt
return nil, fmt.Errorf("state slot %d not equal to latest block header slot %d", state.Slot(), latestBlockHeader.Slot)
}
// Prepare data
// header.state_root = hash_tree_root(state)
stateRoot, err := state.HashTreeRoot(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not get state root")
}
latestBlockHeader.StateRoot = stateRoot[:]
// assert hash_tree_root(header) == hash_tree_root(block.message)
latestBlockHeaderRoot, err := latestBlockHeader.HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "could not get latest block header root")
}
beaconBlockRoot, err := block.Block().HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "could not get block root")
}
if latestBlockHeaderRoot != beaconBlockRoot {
return nil, fmt.Errorf("latest block header root %#x not equal to block root %#x", latestBlockHeaderRoot, beaconBlockRoot)
}
lightClientHeaderContainer, err := lightclient.BlockToLightClientHeader(block)
if err != nil {
return nil, errors.Wrap(err, "could not convert block to light client header")
}
lightClientHeader := lightClientHeaderContainer.GetHeaderCapella()
apiLightClientHeader := &structs.LightClientHeader{
Beacon: structs.BeaconBlockHeaderFromConsensus(migration.V1HeaderToV1Alpha1(lightClientHeader.Beacon)),
}
headerJSON, err := json.Marshal(apiLightClientHeader)
if err != nil {
return nil, errors.Wrap(err, "could not convert header to raw message")
}
currentSyncCommittee, err := state.CurrentSyncCommittee()
if err != nil {
return nil, errors.Wrap(err, "could not get current sync committee")
}
committee := structs.SyncCommitteeFromConsensus(currentSyncCommittee)
currentSyncCommitteeProof, err := state.CurrentSyncCommitteeProof(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not get current sync committee proof")
}
branch := make([]string, fieldparams.NextSyncCommitteeBranchDepth)
branch := make([]string, fieldparams.SyncCommitteeBranchDepth)
for i, proof := range currentSyncCommitteeProof {
branch[i] = hexutil.Encode(proof)
}
beacon := structs.BeaconBlockHeaderFromConsensus(latestBlockHeader)
payloadInterface, err := block.Body().Execution()
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload")
}
transactionsRoot, err := payloadInterface.TransactionsRoot()
if errors.Is(err, consensus_types.ErrUnsupportedField) {
transactions, err := payloadInterface.Transactions()
if err != nil {
return nil, errors.Wrap(err, "could not get transactions")
}
transactionsRootArray, err := ssz.TransactionsRoot(transactions)
if err != nil {
return nil, errors.Wrap(err, "could not get transactions root")
}
transactionsRoot = transactionsRootArray[:]
} else if err != nil {
return nil, errors.Wrap(err, "could not get transactions root")
}
withdrawalsRoot, err := payloadInterface.WithdrawalsRoot()
if errors.Is(err, consensus_types.ErrUnsupportedField) {
withdrawals, err := payloadInterface.Withdrawals()
if err != nil {
return nil, errors.Wrap(err, "could not get withdrawals")
}
withdrawalsRootArray, err := ssz.WithdrawalSliceRoot(withdrawals, fieldparams.MaxWithdrawalsPerPayload)
if err != nil {
return nil, errors.Wrap(err, "could not get withdrawals root")
}
withdrawalsRoot = withdrawalsRootArray[:]
}
executionPayloadHeader := &structs.ExecutionPayloadHeaderCapella{
ParentHash: hexutil.Encode(payloadInterface.ParentHash()),
FeeRecipient: hexutil.Encode(payloadInterface.FeeRecipient()),
StateRoot: hexutil.Encode(payloadInterface.StateRoot()),
ReceiptsRoot: hexutil.Encode(payloadInterface.ReceiptsRoot()),
LogsBloom: hexutil.Encode(payloadInterface.LogsBloom()),
PrevRandao: hexutil.Encode(payloadInterface.PrevRandao()),
BlockNumber: hexutil.EncodeUint64(payloadInterface.BlockNumber()),
GasLimit: hexutil.EncodeUint64(payloadInterface.GasLimit()),
GasUsed: hexutil.EncodeUint64(payloadInterface.GasUsed()),
Timestamp: hexutil.EncodeUint64(payloadInterface.Timestamp()),
ExtraData: hexutil.Encode(payloadInterface.ExtraData()),
BaseFeePerGas: hexutil.Encode(payloadInterface.BaseFeePerGas()),
BlockHash: hexutil.Encode(payloadInterface.BlockHash()),
TransactionsRoot: hexutil.Encode(transactionsRoot),
WithdrawalsRoot: hexutil.Encode(withdrawalsRoot),
}
executionPayloadProof, err := blocks.PayloadProof(ctx, block)
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload proof")
}
executionPayloadProofStr := make([]string, len(executionPayloadProof))
for i, proof := range executionPayloadProof {
executionPayloadProofStr[i] = hexutil.Encode(proof)
}
header := &structs.LightClientHeaderCapella{
Beacon: beacon,
Execution: executionPayloadHeader,
ExecutionBranch: executionPayloadProofStr,
}
// Above shared util function won't calculate state root, so we need to do it manually
stateRoot, err := state.HashTreeRoot(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not get state root")
}
header.Beacon.StateRoot = hexutil.Encode(stateRoot[:])
headerJson, err := json.Marshal(header)
if err != nil {
return nil, errors.Wrap(err, "could not convert header to raw message")
}
// Return result
result := &structs.LightClientBootstrap{
Header: headerJson,
CurrentSyncCommittee: committee,
Header: headerJSON,
CurrentSyncCommittee: structs.SyncCommitteeFromConsensus(currentSyncCommittee),
CurrentSyncCommitteeBranch: branch,
}
return result, nil
}
func createLightClientBootstrapDeneb(ctx context.Context, state state.BeaconState, block interfaces.ReadOnlyBeaconBlock) (*structs.LightClientBootstrap, error) {
func createLightClientBootstrapDeneb(ctx context.Context, state state.BeaconState, block interfaces.ReadOnlySignedBeaconBlock) (*structs.LightClientBootstrap, error) {
// assert compute_epoch_at_slot(state.slot) >= DENEB_FORK_EPOCH
if slots.ToEpoch(state.Slot()) < params.BeaconConfig().DenebForkEpoch {
return nil, fmt.Errorf("creating Deneb light client bootstrap is not supported before Deneb, invalid slot %d", state.Slot())
@@ -243,103 +184,61 @@ func createLightClientBootstrapDeneb(ctx context.Context, state state.BeaconStat
return nil, fmt.Errorf("state slot %d not equal to latest block header slot %d", state.Slot(), latestBlockHeader.Slot)
}
// Prepare data
currentSyncCommittee, err := state.CurrentSyncCommittee()
if err != nil {
return nil, errors.Wrap(err, "could not get current sync committee")
}
committee := structs.SyncCommitteeFromConsensus(currentSyncCommittee)
currentSyncCommitteeProof, err := state.CurrentSyncCommitteeProof(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not get current sync committee proof")
}
branch := make([]string, fieldparams.NextSyncCommitteeBranchDepth)
for i, proof := range currentSyncCommitteeProof {
branch[i] = hexutil.Encode(proof)
}
beacon := structs.BeaconBlockHeaderFromConsensus(latestBlockHeader)
payloadInterface, err := block.Body().Execution()
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload")
}
transactionsRoot, err := payloadInterface.TransactionsRoot()
if errors.Is(err, consensus_types.ErrUnsupportedField) {
transactions, err := payloadInterface.Transactions()
if err != nil {
return nil, errors.Wrap(err, "could not get transactions")
}
transactionsRootArray, err := ssz.TransactionsRoot(transactions)
if err != nil {
return nil, errors.Wrap(err, "could not get transactions root")
}
transactionsRoot = transactionsRootArray[:]
} else if err != nil {
return nil, errors.Wrap(err, "could not get transactions root")
}
withdrawalsRoot, err := payloadInterface.WithdrawalsRoot()
if errors.Is(err, consensus_types.ErrUnsupportedField) {
withdrawals, err := payloadInterface.Withdrawals()
if err != nil {
return nil, errors.Wrap(err, "could not get withdrawals")
}
withdrawalsRootArray, err := ssz.WithdrawalSliceRoot(withdrawals, fieldparams.MaxWithdrawalsPerPayload)
if err != nil {
return nil, errors.Wrap(err, "could not get withdrawals root")
}
withdrawalsRoot = withdrawalsRootArray[:]
}
executionPayloadHeader := &structs.ExecutionPayloadHeaderDeneb{
ParentHash: hexutil.Encode(payloadInterface.ParentHash()),
FeeRecipient: hexutil.Encode(payloadInterface.FeeRecipient()),
StateRoot: hexutil.Encode(payloadInterface.StateRoot()),
ReceiptsRoot: hexutil.Encode(payloadInterface.ReceiptsRoot()),
LogsBloom: hexutil.Encode(payloadInterface.LogsBloom()),
PrevRandao: hexutil.Encode(payloadInterface.PrevRandao()),
BlockNumber: hexutil.EncodeUint64(payloadInterface.BlockNumber()),
GasLimit: hexutil.EncodeUint64(payloadInterface.GasLimit()),
GasUsed: hexutil.EncodeUint64(payloadInterface.GasUsed()),
Timestamp: hexutil.EncodeUint64(payloadInterface.Timestamp()),
ExtraData: hexutil.Encode(payloadInterface.ExtraData()),
BaseFeePerGas: hexutil.Encode(payloadInterface.BaseFeePerGas()),
BlockHash: hexutil.Encode(payloadInterface.BlockHash()),
TransactionsRoot: hexutil.Encode(transactionsRoot),
WithdrawalsRoot: hexutil.Encode(withdrawalsRoot),
}
executionPayloadProof, err := blocks.PayloadProof(ctx, block)
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload proof")
}
executionPayloadProofStr := make([]string, len(executionPayloadProof))
for i, proof := range executionPayloadProof {
executionPayloadProofStr[i] = hexutil.Encode(proof)
}
header := &structs.LightClientHeaderDeneb{
Beacon: beacon,
Execution: executionPayloadHeader,
ExecutionBranch: executionPayloadProofStr,
}
// Above shared util function won't calculate state root, so we need to do it manually
// header.state_root = hash_tree_root(state)
stateRoot, err := state.HashTreeRoot(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not get state root")
}
header.Beacon.StateRoot = hexutil.Encode(stateRoot[:])
latestBlockHeader.StateRoot = stateRoot[:]
headerJson, err := json.Marshal(header)
// assert hash_tree_root(header) == hash_tree_root(block.message)
latestBlockHeaderRoot, err := latestBlockHeader.HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "could not get latest block header root")
}
beaconBlockRoot, err := block.Block().HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "could not get block root")
}
if latestBlockHeaderRoot != beaconBlockRoot {
return nil, fmt.Errorf("latest block header root %#x not equal to block root %#x", latestBlockHeaderRoot, beaconBlockRoot)
}
lightClientHeaderContainer, err := lightclient.BlockToLightClientHeader(block)
if err != nil {
return nil, errors.Wrap(err, "could not convert block to light client header")
}
lightClientHeader := lightClientHeaderContainer.GetHeaderDeneb()
apiLightClientHeader := &structs.LightClientHeader{
Beacon: structs.BeaconBlockHeaderFromConsensus(migration.V1HeaderToV1Alpha1(lightClientHeader.Beacon)),
}
headerJSON, err := json.Marshal(apiLightClientHeader)
if err != nil {
return nil, errors.Wrap(err, "could not convert header to raw message")
}
// Return result
currentSyncCommittee, err := state.CurrentSyncCommittee()
if err != nil {
return nil, errors.Wrap(err, "could not get current sync committee")
}
currentSyncCommitteeProof, err := state.CurrentSyncCommitteeProof(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not get current sync committee proof")
}
var branch []string
switch block.Version() {
case version.Deneb:
branch = make([]string, fieldparams.SyncCommitteeBranchDepth)
case version.Electra:
branch = make([]string, fieldparams.SyncCommitteeBranchDepthElectra)
}
for i, proof := range currentSyncCommitteeProof {
branch[i] = hexutil.Encode(proof)
}
result := &structs.LightClientBootstrap{
Header: headerJson,
CurrentSyncCommittee: committee,
Header: headerJSON,
CurrentSyncCommittee: structs.SyncCommitteeFromConsensus(currentSyncCommittee),
CurrentSyncCommitteeBranch: branch,
}
@@ -351,9 +250,10 @@ func newLightClientUpdateFromBeaconState(
state state.BeaconState,
block interfaces.ReadOnlySignedBeaconBlock,
attestedState state.BeaconState,
attestedBlock interfaces.ReadOnlySignedBeaconBlock,
finalizedBlock interfaces.ReadOnlySignedBeaconBlock,
) (*structs.LightClientUpdate, error) {
result, err := lightclient.NewLightClientUpdateFromBeaconState(ctx, state, block, attestedState, finalizedBlock)
result, err := lightclient.NewLightClientUpdateFromBeaconState(ctx, state, block, attestedState, attestedBlock, finalizedBlock)
if err != nil {
return nil, err
}
@@ -366,9 +266,10 @@ func newLightClientFinalityUpdateFromBeaconState(
state state.BeaconState,
block interfaces.ReadOnlySignedBeaconBlock,
attestedState state.BeaconState,
attestedBlock interfaces.ReadOnlySignedBeaconBlock,
finalizedBlock interfaces.ReadOnlySignedBeaconBlock,
) (*structs.LightClientFinalityUpdate, error) {
result, err := lightclient.NewLightClientFinalityUpdateFromBeaconState(ctx, state, block, attestedState, finalizedBlock)
result, err := lightclient.NewLightClientFinalityUpdateFromBeaconState(ctx, state, block, attestedState, attestedBlock, finalizedBlock)
if err != nil {
return nil, err
}
@@ -381,8 +282,9 @@ func newLightClientOptimisticUpdateFromBeaconState(
state state.BeaconState,
block interfaces.ReadOnlySignedBeaconBlock,
attestedState state.BeaconState,
attestedBlock interfaces.ReadOnlySignedBeaconBlock,
) (*structs.LightClientOptimisticUpdate, error) {
result, err := lightclient.NewLightClientOptimisticUpdateFromBeaconState(ctx, state, block, attestedState)
result, err := lightclient.NewLightClientOptimisticUpdateFromBeaconState(ctx, state, block, attestedState, attestedBlock)
if err != nil {
return nil, err
}
@@ -391,7 +293,7 @@ func newLightClientOptimisticUpdateFromBeaconState(
}
func IsSyncCommitteeUpdate(update *v2.LightClientUpdate) bool {
nextSyncCommitteeBranch := make([][]byte, fieldparams.NextSyncCommitteeBranchDepth)
nextSyncCommitteeBranch := make([][]byte, fieldparams.SyncCommitteeBranchDepth)
return !reflect.DeepEqual(update.NextSyncCommitteeBranch, nextSyncCommitteeBranch)
}

View File

@@ -13,7 +13,7 @@ import (
// When the update has relevant sync committee
func createNonEmptySyncCommitteeBranch() [][]byte {
res := make([][]byte, fieldparams.NextSyncCommitteeBranchDepth)
res := make([][]byte, fieldparams.SyncCommitteeBranchDepth)
res[0] = []byte("xyz")
return res
}
@@ -101,7 +101,7 @@ func TestIsBetterUpdate(t *testing.T) {
}},
},
},
NextSyncCommitteeBranch: make([][]byte, fieldparams.NextSyncCommitteeBranchDepth),
NextSyncCommitteeBranch: make([][]byte, fieldparams.SyncCommitteeBranchDepth),
SignatureSlot: 9999,
},
newUpdate: &ethpbv2.LightClientUpdate{
@@ -147,7 +147,7 @@ func TestIsBetterUpdate(t *testing.T) {
}},
},
},
NextSyncCommitteeBranch: make([][]byte, fieldparams.NextSyncCommitteeBranchDepth),
NextSyncCommitteeBranch: make([][]byte, fieldparams.SyncCommitteeBranchDepth),
SignatureSlot: 9999,
},
expectedResult: false,

View File

@@ -287,6 +287,18 @@ func (s *Server) produceBlockV3(ctx context.Context, w http.ResponseWriter, r *h
handleProduceDenebV3(w, isSSZ, denebBlockContents, v1alpha1resp.PayloadValue, consensusBlockValue)
return
}
blindedElectraBlockContents, ok := v1alpha1resp.Block.(*eth.GenericBeaconBlock_BlindedElectra)
if ok {
w.Header().Set(api.VersionHeader, version.String(version.Electra))
handleProduceBlindedElectraV3(w, isSSZ, blindedElectraBlockContents, v1alpha1resp.PayloadValue, consensusBlockValue)
return
}
electraBlockContents, ok := v1alpha1resp.Block.(*eth.GenericBeaconBlock_Electra)
if ok {
w.Header().Set(api.VersionHeader, version.String(version.Electra))
handleProduceElectraV3(w, isSSZ, electraBlockContents, v1alpha1resp.PayloadValue, consensusBlockValue)
return
}
}
func getConsensusBlockValue(ctx context.Context, blockRewardsFetcher rewards.BlockRewardsFetcher, i interface{} /* block as argument */) (string, *httputil.DefaultJsonError) {
@@ -587,3 +599,74 @@ func handleProduceDenebV3(
Data: jsonBytes,
})
}
func handleProduceBlindedElectraV3(
w http.ResponseWriter,
isSSZ bool,
blk *eth.GenericBeaconBlock_BlindedElectra,
executionPayloadValue string,
consensusPayloadValue string,
) {
if isSSZ {
sszResp, err := blk.BlindedElectra.MarshalSSZ()
if err != nil {
httputil.HandleError(w, err.Error(), http.StatusInternalServerError)
return
}
httputil.WriteSsz(w, sszResp, "blindedElectraBlockContents.ssz")
return
}
blindedBlock, err := structs.BlindedBeaconBlockElectraFromConsensus(blk.BlindedElectra)
if err != nil {
httputil.HandleError(w, err.Error(), http.StatusInternalServerError)
return
}
jsonBytes, err := json.Marshal(blindedBlock)
if err != nil {
httputil.HandleError(w, err.Error(), http.StatusInternalServerError)
return
}
httputil.WriteJson(w, &structs.ProduceBlockV3Response{
Version: version.String(version.Electra),
ExecutionPayloadBlinded: true,
ExecutionPayloadValue: executionPayloadValue,
ConsensusBlockValue: consensusPayloadValue,
Data: jsonBytes,
})
}
func handleProduceElectraV3(
w http.ResponseWriter,
isSSZ bool,
blk *eth.GenericBeaconBlock_Electra,
executionPayloadValue string,
consensusBlockValue string,
) {
if isSSZ {
sszResp, err := blk.Electra.MarshalSSZ()
if err != nil {
httputil.HandleError(w, err.Error(), http.StatusInternalServerError)
return
}
httputil.WriteSsz(w, sszResp, "electraBlockContents.ssz")
return
}
blockContents, err := structs.BeaconBlockContentsElectraFromConsensus(blk.Electra)
if err != nil {
httputil.HandleError(w, err.Error(), http.StatusInternalServerError)
return
}
jsonBytes, err := json.Marshal(blockContents)
if err != nil {
httputil.HandleError(w, err.Error(), http.StatusInternalServerError)
return
}
httputil.WriteJson(w, &structs.ProduceBlockV3Response{
Version: version.String(version.Electra),
ExecutionPayloadBlinded: false,
ExecutionPayloadValue: executionPayloadValue, // mev not available at this point
ConsensusBlockValue: consensusBlockValue,
Data: jsonBytes,
})
}

View File

@@ -308,6 +308,75 @@ func TestProduceBlockV2(t *testing.T) {
assert.Equal(t, http.StatusInternalServerError, e.Code)
assert.StringContains(t, "Prepared block is blinded", e.Message)
})
t.Run("Electra", func(t *testing.T) {
var block *structs.SignedBeaconBlockContentsElectra
err = json.Unmarshal([]byte(rpctesting.ElectraBlockContents), &block)
require.NoError(t, err)
jsonBytes, err := json.Marshal(block.ToUnsigned())
require.NoError(t, err)
v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
Slot: 1,
RandaoReveal: bRandao,
Graffiti: bGraffiti,
SkipMevBoost: true,
}).Return(
func() (*eth.GenericBeaconBlock, error) {
b, err := block.ToUnsigned().ToGeneric()
require.NoError(t, err)
b.PayloadValue = "2000"
return b, nil
}())
server := &Server{
V1Alpha1Server: v1alpha1Server,
SyncChecker: syncChecker,
OptimisticModeFetcher: chainService,
BlockRewardFetcher: rewardFetcher,
}
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v2/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
server.ProduceBlockV2(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
want := fmt.Sprintf(`{"version":"electra","execution_payload_blinded":false,"execution_payload_value":"2000","consensus_block_value":"10000000000","data":%s}`, string(jsonBytes))
body := strings.ReplaceAll(writer.Body.String(), "\n", "")
require.Equal(t, want, body)
require.Equal(t, "electra", writer.Header().Get(api.VersionHeader))
})
t.Run("Blinded Electra", func(t *testing.T) {
var block *structs.SignedBlindedBeaconBlockElectra
err = json.Unmarshal([]byte(rpctesting.BlindedElectraBlock), &block)
require.NoError(t, err)
v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
Slot: 1,
RandaoReveal: bRandao,
Graffiti: bGraffiti,
SkipMevBoost: true,
}).Return(
func() (*eth.GenericBeaconBlock, error) {
return block.Message.ToGeneric()
}())
server := &Server{
V1Alpha1Server: v1alpha1Server,
SyncChecker: syncChecker,
OptimisticModeFetcher: chainService,
BlockRewardFetcher: rewardFetcher,
}
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v2/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
server.ProduceBlockV2(writer, request)
assert.Equal(t, http.StatusInternalServerError, writer.Code)
e := &httputil.DefaultJsonError{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), e))
assert.Equal(t, http.StatusInternalServerError, e.Code)
assert.StringContains(t, "Prepared block is blinded", e.Message)
})
t.Run("invalid query parameter slot empty", func(t *testing.T) {
v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
server := &Server{
@@ -650,6 +719,76 @@ func TestProduceBlockV2SSZ(t *testing.T) {
BlockRewardFetcher: rewardFetcher,
}
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v2/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
request.Header.Set("Accept", api.OctetStreamMediaType)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
server.ProduceBlockV2(writer, request)
assert.Equal(t, http.StatusInternalServerError, writer.Code)
e := &httputil.DefaultJsonError{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), e))
assert.Equal(t, http.StatusInternalServerError, e.Code)
assert.StringContains(t, "Prepared block is blinded", e.Message)
})
t.Run("Electra", func(t *testing.T) {
var block *structs.SignedBeaconBlockContentsElectra
err = json.Unmarshal([]byte(rpctesting.ElectraBlockContents), &block)
require.NoError(t, err)
v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
Slot: 1,
RandaoReveal: bRandao,
Graffiti: bGraffiti,
SkipMevBoost: true,
}).Return(
func() (*eth.GenericBeaconBlock, error) {
return block.ToUnsigned().ToGeneric()
}())
server := &Server{
V1Alpha1Server: v1alpha1Server,
SyncChecker: syncChecker,
OptimisticModeFetcher: chainService,
BlockRewardFetcher: rewardFetcher,
}
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v2/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
request.Header.Set("Accept", api.OctetStreamMediaType)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
server.ProduceBlockV2(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
g, err := block.ToUnsigned().ToGeneric()
require.NoError(t, err)
bl, ok := g.Block.(*eth.GenericBeaconBlock_Electra)
require.Equal(t, true, ok)
ssz, err := bl.Electra.MarshalSSZ()
require.NoError(t, err)
require.Equal(t, string(ssz), writer.Body.String())
require.Equal(t, "electra", writer.Header().Get(api.VersionHeader))
})
t.Run("Blinded Electra", func(t *testing.T) {
var block *structs.SignedBlindedBeaconBlockElectra
err = json.Unmarshal([]byte(rpctesting.BlindedElectraBlock), &block)
require.NoError(t, err)
v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
Slot: 1,
RandaoReveal: bRandao,
Graffiti: bGraffiti,
SkipMevBoost: true,
}).Return(
func() (*eth.GenericBeaconBlock, error) {
return block.Message.ToGeneric()
}())
server := &Server{
V1Alpha1Server: v1alpha1Server,
SyncChecker: syncChecker,
OptimisticModeFetcher: chainService,
BlockRewardFetcher: rewardFetcher,
}
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v2/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
request.Header.Set("Accept", api.OctetStreamMediaType)
writer := httptest.NewRecorder()
@@ -944,6 +1083,75 @@ func TestProduceBlindedBlock(t *testing.T) {
require.Equal(t, want, body)
require.Equal(t, "deneb", writer.Header().Get(api.VersionHeader))
})
t.Run("Electra", func(t *testing.T) {
var block *structs.SignedBeaconBlockContentsElectra
err = json.Unmarshal([]byte(rpctesting.ElectraBlockContents), &block)
require.NoError(t, err)
v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
Slot: 1,
RandaoReveal: bRandao,
Graffiti: bGraffiti,
SkipMevBoost: false,
}).Return(
func() (*eth.GenericBeaconBlock, error) {
return block.ToUnsigned().ToGeneric()
}())
server := &Server{
V1Alpha1Server: v1alpha1Server,
SyncChecker: syncChecker,
OptimisticModeFetcher: chainService,
BlockRewardFetcher: rewardFetcher,
}
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v1/validator/blinded_blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
server.ProduceBlindedBlock(writer, request)
assert.Equal(t, http.StatusInternalServerError, writer.Code)
e := &httputil.DefaultJsonError{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), e))
assert.Equal(t, http.StatusInternalServerError, e.Code)
assert.StringContains(t, "Prepared block is not blinded", e.Message)
})
t.Run("Blinded Electra", func(t *testing.T) {
var block *structs.SignedBlindedBeaconBlockElectra
err = json.Unmarshal([]byte(rpctesting.BlindedElectraBlock), &block)
require.NoError(t, err)
jsonBytes, err := json.Marshal(block.Message)
require.NoError(t, err)
v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
Slot: 1,
RandaoReveal: bRandao,
Graffiti: bGraffiti,
SkipMevBoost: false,
}).Return(
func() (*eth.GenericBeaconBlock, error) {
b, err := block.Message.ToGeneric()
require.NoError(t, err)
b.PayloadValue = "2000"
return b, nil
}())
server := &Server{
V1Alpha1Server: v1alpha1Server,
SyncChecker: syncChecker,
OptimisticModeFetcher: chainService,
BlockRewardFetcher: rewardFetcher,
}
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v1/validator/blinded_blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
server.ProduceBlindedBlock(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
want := fmt.Sprintf(`{"version":"electra","execution_payload_blinded":true,"execution_payload_value":"2000","consensus_block_value":"10000000000","data":%s}`, string(jsonBytes))
body := strings.ReplaceAll(writer.Body.String(), "\n", "")
require.Equal(t, want, body)
require.Equal(t, "electra", writer.Header().Get(api.VersionHeader))
})
t.Run("invalid query parameter slot empty", func(t *testing.T) {
v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
server := &Server{
@@ -1309,6 +1517,82 @@ func TestProduceBlockV3(t *testing.T) {
require.Equal(t, "deneb", writer.Header().Get(api.VersionHeader))
require.Equal(t, "10000000000", writer.Header().Get(api.ConsensusBlockValueHeader))
})
t.Run("Electra", func(t *testing.T) {
var block *structs.SignedBeaconBlockContentsElectra
err := json.Unmarshal([]byte(rpctesting.ElectraBlockContents), &block)
require.NoError(t, err)
jsonBytes, err := json.Marshal(block.ToUnsigned())
require.NoError(t, err)
v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
Slot: 1,
RandaoReveal: bRandao,
Graffiti: bGraffiti,
SkipMevBoost: false,
}).Return(
func() (*eth.GenericBeaconBlock, error) {
b, err := block.ToUnsigned().ToGeneric()
require.NoError(t, err)
b.PayloadValue = "2000"
return b, nil
}())
server := &Server{
V1Alpha1Server: v1alpha1Server,
SyncChecker: syncChecker,
OptimisticModeFetcher: chainService,
BlockRewardFetcher: rewardFetcher,
}
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
server.ProduceBlockV3(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
want := fmt.Sprintf(`{"version":"electra","execution_payload_blinded":false,"execution_payload_value":"2000","consensus_block_value":"10000000000","data":%s}`, string(jsonBytes))
body := strings.ReplaceAll(writer.Body.String(), "\n", "")
require.Equal(t, want, body)
require.Equal(t, "false", writer.Header().Get(api.ExecutionPayloadBlindedHeader))
require.Equal(t, "2000", writer.Header().Get(api.ExecutionPayloadValueHeader))
require.Equal(t, "electra", writer.Header().Get(api.VersionHeader))
require.Equal(t, "10000000000", writer.Header().Get(api.ConsensusBlockValueHeader))
})
t.Run("Blinded Electra", func(t *testing.T) {
var block *structs.SignedBlindedBeaconBlockElectra
err := json.Unmarshal([]byte(rpctesting.BlindedElectraBlock), &block)
require.NoError(t, err)
jsonBytes, err := json.Marshal(block.Message)
require.NoError(t, err)
v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
Slot: 1,
RandaoReveal: bRandao,
Graffiti: bGraffiti,
SkipMevBoost: false,
}).Return(
func() (*eth.GenericBeaconBlock, error) {
b, err := block.Message.ToGeneric()
require.NoError(t, err)
b.PayloadValue = "2000"
return b, nil
}())
server := &Server{
V1Alpha1Server: v1alpha1Server,
SyncChecker: syncChecker,
OptimisticModeFetcher: chainService,
BlockRewardFetcher: rewardFetcher,
}
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
server.ProduceBlockV3(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
want := fmt.Sprintf(`{"version":"electra","execution_payload_blinded":true,"execution_payload_value":"2000","consensus_block_value":"10000000000","data":%s}`, string(jsonBytes))
body := strings.ReplaceAll(writer.Body.String(), "\n", "")
require.Equal(t, want, body)
require.Equal(t, "true", writer.Header().Get(api.ExecutionPayloadBlindedHeader))
require.Equal(t, "2000", writer.Header().Get(api.ExecutionPayloadValueHeader))
require.Equal(t, "electra", writer.Header().Get(api.VersionHeader))
require.Equal(t, "10000000000", writer.Header().Get(api.ConsensusBlockValueHeader))
})
t.Run("invalid query parameter slot empty", func(t *testing.T) {
v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
server := &Server{
@@ -1697,4 +1981,86 @@ func TestProduceBlockV3SSZ(t *testing.T) {
require.Equal(t, "deneb", writer.Header().Get(api.VersionHeader))
require.Equal(t, "10000000000", writer.Header().Get(api.ConsensusBlockValueHeader))
})
t.Run("Electra", func(t *testing.T) {
var block *structs.SignedBeaconBlockContentsElectra
err := json.Unmarshal([]byte(rpctesting.ElectraBlockContents), &block)
require.NoError(t, err)
v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
Slot: 1,
RandaoReveal: bRandao,
Graffiti: bGraffiti,
SkipMevBoost: false,
}).Return(
func() (*eth.GenericBeaconBlock, error) {
b, err := block.ToUnsigned().ToGeneric()
require.NoError(t, err)
b.PayloadValue = "2000"
return b, nil
}())
server := &Server{
V1Alpha1Server: v1alpha1Server,
SyncChecker: syncChecker,
OptimisticModeFetcher: chainService,
BlockRewardFetcher: rewardFetcher,
}
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
request.Header.Set("Accept", api.OctetStreamMediaType)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
server.ProduceBlockV3(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
g, err := block.ToUnsigned().ToGeneric()
require.NoError(t, err)
bl, ok := g.Block.(*eth.GenericBeaconBlock_Electra)
require.Equal(t, true, ok)
ssz, err := bl.Electra.MarshalSSZ()
require.NoError(t, err)
require.Equal(t, string(ssz), writer.Body.String())
require.Equal(t, "false", writer.Header().Get(api.ExecutionPayloadBlindedHeader))
require.Equal(t, "2000", writer.Header().Get(api.ExecutionPayloadValueHeader))
require.Equal(t, "electra", writer.Header().Get(api.VersionHeader))
require.Equal(t, "10000000000", writer.Header().Get(api.ConsensusBlockValueHeader))
})
t.Run("Blinded Electra", func(t *testing.T) {
var block *structs.SignedBlindedBeaconBlockElectra
err := json.Unmarshal([]byte(rpctesting.BlindedElectraBlock), &block)
require.NoError(t, err)
v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
Slot: 1,
RandaoReveal: bRandao,
Graffiti: bGraffiti,
SkipMevBoost: false,
}).Return(
func() (*eth.GenericBeaconBlock, error) {
b, err := block.Message.ToGeneric()
require.NoError(t, err)
b.PayloadValue = "2000"
return b, nil
}())
server := &Server{
V1Alpha1Server: v1alpha1Server,
SyncChecker: syncChecker,
OptimisticModeFetcher: chainService,
BlockRewardFetcher: rewardFetcher,
}
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
request.Header.Set("Accept", api.OctetStreamMediaType)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
server.ProduceBlockV3(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
g, err := block.Message.ToGeneric()
require.NoError(t, err)
bl, ok := g.Block.(*eth.GenericBeaconBlock_BlindedElectra)
require.Equal(t, true, ok)
ssz, err := bl.BlindedElectra.MarshalSSZ()
require.NoError(t, err)
require.Equal(t, string(ssz), writer.Body.String())
require.Equal(t, "true", writer.Header().Get(api.ExecutionPayloadBlindedHeader))
require.Equal(t, "2000", writer.Header().Get(api.ExecutionPayloadValueHeader))
require.Equal(t, "electra", writer.Header().Get(api.VersionHeader))
require.Equal(t, "10000000000", writer.Header().Get(api.ConsensusBlockValueHeader))
})
}

View File

@@ -14,6 +14,7 @@ go_library(
"//beacon-chain/blockchain:go_default_library",
"//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/db:go_default_library",
"//beacon-chain/p2p:go_default_library",
"//beacon-chain/rpc/core:go_default_library",
"//beacon-chain/rpc/eth/helpers:go_default_library",
"//beacon-chain/rpc/eth/shared:go_default_library",
@@ -22,8 +23,10 @@ go_library(
"//beacon-chain/state/stategen:go_default_library",
"//beacon-chain/sync:go_default_library",
"//config/params:go_default_library",
"//consensus-types/blocks:go_default_library",
"//consensus-types/primitives:go_default_library",
"//consensus-types/validator:go_default_library",
"//encoding/bytesutil:go_default_library",
"//monitoring/tracing/trace:go_default_library",
"//network/httputil:go_default_library",
"//proto/eth/v1:go_default_library",
@@ -47,13 +50,16 @@ go_test(
"//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/db/testing:go_default_library",
"//beacon-chain/forkchoice/doubly-linked-tree:go_default_library",
"//beacon-chain/p2p/testing:go_default_library",
"//beacon-chain/rpc/core:go_default_library",
"//beacon-chain/rpc/lookup:go_default_library",
"//beacon-chain/rpc/prysm/testing:go_default_library",
"//beacon-chain/rpc/testutil:go_default_library",
"//beacon-chain/state:go_default_library",
"//beacon-chain/state/state-native:go_default_library",
"//beacon-chain/state/stategen:go_default_library",
"//beacon-chain/state/stategen/mock:go_default_library",
"//beacon-chain/sync/initial-sync/testing:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//consensus-types/blocks:go_default_library",

View File

@@ -15,7 +15,9 @@ import (
"github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/core"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/eth/shared"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
"github.com/prysmaticlabs/prysm/v5/network/httputil"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
@@ -183,3 +185,52 @@ func (s *Server) GetChainHead(w http.ResponseWriter, r *http.Request) {
}
httputil.WriteJson(w, response)
}
func (s *Server) PublishBlobs(w http.ResponseWriter, r *http.Request) {
ctx, span := trace.StartSpan(r.Context(), "beacon.PublishBlobs")
defer span.End()
if shared.IsSyncing(r.Context(), w, s.SyncChecker, s.HeadFetcher, s.TimeFetcher, s.OptimisticModeFetcher) {
return
}
var req structs.PublishBlobsRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
httputil.HandleError(w, "Could not decode JSON request body", http.StatusBadRequest)
return
}
if req.BlobSidecars == nil {
httputil.HandleError(w, "Missing blob sidecars", http.StatusBadRequest)
return
}
root, err := bytesutil.DecodeHexWithLength(req.BlockRoot, 32)
if err != nil {
httputil.HandleError(w, "Could not decode block root: "+err.Error(), http.StatusBadRequest)
return
}
for _, blobSidecar := range req.BlobSidecars.Sidecars {
sc, err := blobSidecar.ToConsensus()
if err != nil {
httputil.HandleError(w, "Could not decode blob sidecar: "+err.Error(), http.StatusBadRequest)
return
}
readOnlySc, err := blocks.NewROBlobWithRoot(sc, bytesutil.ToBytes32(root))
if err != nil {
httputil.HandleError(w, "Could not create read-only blob: "+err.Error(), http.StatusInternalServerError)
return
}
verifiedBlob := blocks.NewVerifiedROBlob(readOnlySc)
if err := s.BlobReceiver.ReceiveBlob(ctx, verifiedBlob); err != nil {
httputil.HandleError(w, "Could not receive blob: "+err.Error(), http.StatusInternalServerError)
return
}
if err := s.Broadcaster.BroadcastBlob(ctx, sc.Index, sc); err != nil {
httputil.HandleError(w, "Failed to broadcast blob: "+err.Error(), http.StatusInternalServerError)
return
}
}
}

View File

@@ -18,10 +18,13 @@ import (
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
dbTest "github.com/prysmaticlabs/prysm/v5/beacon-chain/db/testing"
doublylinkedtree "github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice/doubly-linked-tree"
mockp2p "github.com/prysmaticlabs/prysm/v5/beacon-chain/p2p/testing"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/core"
rpctesting "github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/prysm/testing"
state_native "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state/stategen"
mockstategen "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/stategen/mock"
mockSync "github.com/prysmaticlabs/prysm/v5/beacon-chain/sync/initial-sync/testing"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
@@ -870,3 +873,163 @@ func TestServer_GetChainHead(t *testing.T) {
assert.DeepEqual(t, hexutil.Encode(fRoot[:]), ch.FinalizedBlockRoot, "Unexpected FinalizedBlockRoot")
assert.Equal(t, false, ch.OptimisticStatus)
}
func TestPublishBlobs_InvalidJson(t *testing.T) {
server := &Server{
BlobReceiver: &chainMock.ChainService{},
Broadcaster: &mockp2p.MockBroadcaster{},
SyncChecker: &mockSync.Sync{IsSyncing: false},
}
request := httptest.NewRequest(http.MethodPost, "http://foo.example", bytes.NewReader([]byte(rpctesting.InvalidJson)))
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
server.PublishBlobs(writer, request)
assert.Equal(t, http.StatusBadRequest, writer.Code)
assert.StringContains(t, "Could not decode JSON request body", writer.Body.String())
assert.Equal(t, len(server.BlobReceiver.(*chainMock.ChainService).Blobs), 0)
assert.Equal(t, server.Broadcaster.(*mockp2p.MockBroadcaster).BroadcastCalled.Load(), false)
}
func TestPublishBlobs_MissingBlob(t *testing.T) {
server := &Server{
BlobReceiver: &chainMock.ChainService{},
Broadcaster: &mockp2p.MockBroadcaster{},
SyncChecker: &mockSync.Sync{IsSyncing: false},
}
request := httptest.NewRequest(http.MethodPost, "http://foo.example", bytes.NewReader([]byte(rpctesting.PublishBlobsRequestMissingBlob)))
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
server.PublishBlobs(writer, request)
assert.Equal(t, http.StatusBadRequest, writer.Code)
assert.StringContains(t, "Could not decode blob sidecar", writer.Body.String())
assert.Equal(t, len(server.BlobReceiver.(*chainMock.ChainService).Blobs), 0)
assert.Equal(t, server.Broadcaster.(*mockp2p.MockBroadcaster).BroadcastCalled.Load(), false)
}
func TestPublishBlobs_MissingSignedBlockHeader(t *testing.T) {
server := &Server{
BlobReceiver: &chainMock.ChainService{},
Broadcaster: &mockp2p.MockBroadcaster{},
SyncChecker: &mockSync.Sync{IsSyncing: false},
}
request := httptest.NewRequest(http.MethodPost, "http://foo.example", bytes.NewReader([]byte(rpctesting.PublishBlobsRequestMissingSignedBlockHeader)))
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
server.PublishBlobs(writer, request)
assert.Equal(t, http.StatusBadRequest, writer.Code)
assert.StringContains(t, "Could not decode blob sidecar", writer.Body.String())
assert.Equal(t, len(server.BlobReceiver.(*chainMock.ChainService).Blobs), 0)
assert.Equal(t, server.Broadcaster.(*mockp2p.MockBroadcaster).BroadcastCalled.Load(), false)
}
func TestPublishBlobs_MissingSidecars(t *testing.T) {
server := &Server{
BlobReceiver: &chainMock.ChainService{},
Broadcaster: &mockp2p.MockBroadcaster{},
SyncChecker: &mockSync.Sync{IsSyncing: false},
}
request := httptest.NewRequest(http.MethodPost, "http://foo.example", bytes.NewReader([]byte(rpctesting.PublishBlobsRequestMissingSidecars)))
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
server.PublishBlobs(writer, request)
assert.Equal(t, http.StatusBadRequest, writer.Code)
assert.StringContains(t, "Missing blob sidecars", writer.Body.String())
assert.Equal(t, len(server.BlobReceiver.(*chainMock.ChainService).Blobs), 0)
assert.Equal(t, server.Broadcaster.(*mockp2p.MockBroadcaster).BroadcastCalled.Load(), false)
}
func TestPublishBlobs_EmptySidecarsList(t *testing.T) {
server := &Server{
BlobReceiver: &chainMock.ChainService{},
Broadcaster: &mockp2p.MockBroadcaster{},
SyncChecker: &mockSync.Sync{IsSyncing: false},
}
request := httptest.NewRequest(http.MethodPost, "http://foo.example", bytes.NewReader([]byte(rpctesting.PublishBlobsRequestEmptySidecarsList)))
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
server.PublishBlobs(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
assert.Equal(t, len(server.BlobReceiver.(*chainMock.ChainService).Blobs), 0)
assert.Equal(t, server.Broadcaster.(*mockp2p.MockBroadcaster).BroadcastCalled.Load(), false)
}
func TestPublishBlobs_NullSidecar(t *testing.T) {
server := &Server{
BlobReceiver: &chainMock.ChainService{},
Broadcaster: &mockp2p.MockBroadcaster{},
SyncChecker: &mockSync.Sync{IsSyncing: false},
}
request := httptest.NewRequest(http.MethodPost, "http://foo.example", bytes.NewReader([]byte(rpctesting.PublishBlobsRequestNullSidecar)))
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
server.PublishBlobs(writer, request)
assert.Equal(t, http.StatusBadRequest, writer.Code)
assert.StringContains(t, "Could not decode blob sidecar", writer.Body.String())
assert.Equal(t, len(server.BlobReceiver.(*chainMock.ChainService).Blobs), 0)
assert.Equal(t, server.Broadcaster.(*mockp2p.MockBroadcaster).BroadcastCalled.Load(), false)
}
func TestPublishBlobs_SeveralFieldsMissing(t *testing.T) {
server := &Server{
BlobReceiver: &chainMock.ChainService{},
Broadcaster: &mockp2p.MockBroadcaster{},
SyncChecker: &mockSync.Sync{IsSyncing: false},
}
request := httptest.NewRequest(http.MethodPost, "http://foo.example", bytes.NewReader([]byte(rpctesting.PublishBlobsRequestSeveralFieldsMissing)))
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
server.PublishBlobs(writer, request)
assert.Equal(t, http.StatusBadRequest, writer.Code)
assert.StringContains(t, "Could not decode blob sidecar", writer.Body.String())
assert.Equal(t, len(server.BlobReceiver.(*chainMock.ChainService).Blobs), 0)
assert.Equal(t, server.Broadcaster.(*mockp2p.MockBroadcaster).BroadcastCalled.Load(), false)
}
func TestPublishBlobs_BadBlockRoot(t *testing.T) {
server := &Server{
BlobReceiver: &chainMock.ChainService{},
Broadcaster: &mockp2p.MockBroadcaster{},
SyncChecker: &mockSync.Sync{IsSyncing: false},
}
request := httptest.NewRequest(http.MethodPost, "http://foo.example", bytes.NewReader([]byte(rpctesting.PublishBlobsRequestBadBlockRoot)))
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
server.PublishBlobs(writer, request)
assert.Equal(t, http.StatusBadRequest, writer.Code)
assert.StringContains(t, "Could not decode block root", writer.Body.String())
assert.Equal(t, len(server.BlobReceiver.(*chainMock.ChainService).Blobs), 0)
assert.Equal(t, server.Broadcaster.(*mockp2p.MockBroadcaster).BroadcastCalled.Load(), false)
}
func TestPublishBlobs(t *testing.T) {
server := &Server{
BlobReceiver: &chainMock.ChainService{},
Broadcaster: &mockp2p.MockBroadcaster{},
SyncChecker: &mockSync.Sync{IsSyncing: false},
}
request := httptest.NewRequest(http.MethodPost, "http://foo.example", bytes.NewReader([]byte(rpctesting.PublishBlobsRequest)))
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
server.PublishBlobs(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
assert.Equal(t, len(server.BlobReceiver.(*chainMock.ChainService).Blobs), 1)
assert.Equal(t, server.Broadcaster.(*mockp2p.MockBroadcaster).BroadcastCalled.Load(), true)
}

View File

@@ -3,6 +3,7 @@ package beacon
import (
"github.com/prysmaticlabs/prysm/v5/beacon-chain/blockchain"
beacondb "github.com/prysmaticlabs/prysm/v5/beacon-chain/db"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/p2p"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/core"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/lookup"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state/stategen"
@@ -20,4 +21,6 @@ type Server struct {
ChainInfoFetcher blockchain.ChainInfoFetcher
FinalizationFetcher blockchain.FinalizationFetcher
CoreService *core.Service
Broadcaster p2p.Broadcaster
BlobReceiver blockchain.BlobReceiver
}

View File

@@ -0,0 +1,9 @@
load("@prysm//tools/go:def.bzl", "go_library")
go_library(
name = "go_default_library",
testonly = True,
srcs = ["json.go"],
importpath = "github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/prysm/testing",
visibility = ["//visibility:public"],
)

File diff suppressed because one or more lines are too long

View File

@@ -217,10 +217,10 @@ func (a proposerAtts) sort() (proposerAtts, error) {
return a, nil
}
if features.Get().EnableCommitteeAwarePacking {
return a.sortBySlotAndCommittee()
if features.Get().DisableCommitteeAwarePacking {
return a.sortByProfitabilityUsingMaxCover()
}
return a.sortByProfitabilityUsingMaxCover()
return a.sortBySlotAndCommittee()
}
// Separate attestations by slot, as slot number takes higher precedence when sorting.

View File

@@ -21,6 +21,11 @@ import (
)
func TestProposer_ProposerAtts_sort(t *testing.T) {
feat := features.Get()
feat.DisableCommitteeAwarePacking = true
reset := features.InitWithReset(feat)
defer reset()
type testData struct {
slot primitives.Slot
bits bitfield.Bitlist
@@ -186,11 +191,6 @@ func TestProposer_ProposerAtts_committeeAwareSort(t *testing.T) {
}
t.Run("no atts", func(t *testing.T) {
feat := features.Get()
feat.EnableCommitteeAwarePacking = true
reset := features.InitWithReset(feat)
defer reset()
atts := getAtts([]testData{})
want := getAtts([]testData{})
atts, err := atts.sort()
@@ -201,11 +201,6 @@ func TestProposer_ProposerAtts_committeeAwareSort(t *testing.T) {
})
t.Run("single att", func(t *testing.T) {
feat := features.Get()
feat.EnableCommitteeAwarePacking = true
reset := features.InitWithReset(feat)
defer reset()
atts := getAtts([]testData{
{4, bitfield.Bitlist{0b11100000, 0b1}},
})
@@ -220,11 +215,6 @@ func TestProposer_ProposerAtts_committeeAwareSort(t *testing.T) {
})
t.Run("single att per slot", func(t *testing.T) {
feat := features.Get()
feat.EnableCommitteeAwarePacking = true
reset := features.InitWithReset(feat)
defer reset()
atts := getAtts([]testData{
{1, bitfield.Bitlist{0b11000000, 0b1}},
{4, bitfield.Bitlist{0b11100000, 0b1}},
@@ -241,10 +231,6 @@ func TestProposer_ProposerAtts_committeeAwareSort(t *testing.T) {
})
t.Run("two atts on one of the slots", func(t *testing.T) {
feat := features.Get()
feat.EnableCommitteeAwarePacking = true
reset := features.InitWithReset(feat)
defer reset()
atts := getAtts([]testData{
{1, bitfield.Bitlist{0b11000000, 0b1}},
@@ -263,11 +249,6 @@ func TestProposer_ProposerAtts_committeeAwareSort(t *testing.T) {
})
t.Run("compare to native sort", func(t *testing.T) {
feat := features.Get()
feat.EnableCommitteeAwarePacking = true
reset := features.InitWithReset(feat)
defer reset()
// The max-cover based approach will select 0b00001100 instead, despite lower bit count
// (since it has two new/unknown bits).
t.Run("max-cover", func(t *testing.T) {
@@ -289,11 +270,6 @@ func TestProposer_ProposerAtts_committeeAwareSort(t *testing.T) {
})
t.Run("multiple slots", func(t *testing.T) {
feat := features.Get()
feat.EnableCommitteeAwarePacking = true
reset := features.InitWithReset(feat)
defer reset()
atts := getAtts([]testData{
{2, bitfield.Bitlist{0b11100000, 0b1}},
{4, bitfield.Bitlist{0b11100000, 0b1}},
@@ -316,11 +292,6 @@ func TestProposer_ProposerAtts_committeeAwareSort(t *testing.T) {
})
t.Run("follows max-cover", func(t *testing.T) {
feat := features.Get()
feat.EnableCommitteeAwarePacking = true
reset := features.InitWithReset(feat)
defer reset()
// Items at slot 4 must be first split into two lists by max-cover, with
// 0b10000011 being selected and 0b11100001 being leftover (despite naive bit count suggesting otherwise).
atts := getAtts([]testData{
@@ -350,11 +321,6 @@ func TestProposer_ProposerAtts_committeeAwareSort(t *testing.T) {
func TestProposer_sort_DifferentCommittees(t *testing.T) {
t.Run("one att per committee", func(t *testing.T) {
feat := features.Get()
feat.EnableCommitteeAwarePacking = true
reset := features.InitWithReset(feat)
defer reset()
c1_a1 := util.HydrateAttestation(&ethpb.Attestation{AggregationBits: bitfield.Bitlist{0b11111000, 0b1}, Data: &ethpb.AttestationData{CommitteeIndex: 1}})
c2_a1 := util.HydrateAttestation(&ethpb.Attestation{AggregationBits: bitfield.Bitlist{0b11100000, 0b1}, Data: &ethpb.AttestationData{CommitteeIndex: 2}})
atts := proposerAtts{c1_a1, c2_a1}
@@ -364,11 +330,6 @@ func TestProposer_sort_DifferentCommittees(t *testing.T) {
assert.DeepEqual(t, want, atts)
})
t.Run("multiple atts per committee", func(t *testing.T) {
feat := features.Get()
feat.EnableCommitteeAwarePacking = true
reset := features.InitWithReset(feat)
defer reset()
c1_a1 := util.HydrateAttestation(&ethpb.Attestation{AggregationBits: bitfield.Bitlist{0b11111100, 0b1}, Data: &ethpb.AttestationData{CommitteeIndex: 1}})
c1_a2 := util.HydrateAttestation(&ethpb.Attestation{AggregationBits: bitfield.Bitlist{0b10000010, 0b1}, Data: &ethpb.AttestationData{CommitteeIndex: 1}})
c2_a1 := util.HydrateAttestation(&ethpb.Attestation{AggregationBits: bitfield.Bitlist{0b11110000, 0b1}, Data: &ethpb.AttestationData{CommitteeIndex: 2}})
@@ -381,11 +342,6 @@ func TestProposer_sort_DifferentCommittees(t *testing.T) {
assert.DeepEqual(t, want, atts)
})
t.Run("multiple atts per committee, multiple slots", func(t *testing.T) {
feat := features.Get()
feat.EnableCommitteeAwarePacking = true
reset := features.InitWithReset(feat)
defer reset()
s2_c1_a1 := util.HydrateAttestation(&ethpb.Attestation{AggregationBits: bitfield.Bitlist{0b11111100, 0b1}, Data: &ethpb.AttestationData{Slot: 2, CommitteeIndex: 1}})
s2_c1_a2 := util.HydrateAttestation(&ethpb.Attestation{AggregationBits: bitfield.Bitlist{0b10000010, 0b1}, Data: &ethpb.AttestationData{Slot: 2, CommitteeIndex: 1}})
s2_c2_a1 := util.HydrateAttestation(&ethpb.Attestation{AggregationBits: bitfield.Bitlist{0b11110000, 0b1}, Data: &ethpb.AttestationData{Slot: 2, CommitteeIndex: 2}})

View File

@@ -48,7 +48,7 @@ type Flags struct {
EnableDoppelGanger bool // EnableDoppelGanger enables doppelganger protection on startup for the validator.
EnableHistoricalSpaceRepresentation bool // EnableHistoricalSpaceRepresentation enables the saving of registry validators in separate buckets to save space
EnableBeaconRESTApi bool // EnableBeaconRESTApi enables experimental usage of the beacon REST API by the validator when querying a beacon node
EnableCommitteeAwarePacking bool // EnableCommitteeAwarePacking TODO
DisableCommitteeAwarePacking bool // DisableCommitteeAwarePacking changes the attestation packing algorithm to one that is not aware of attesting committees.
// Logging related toggles.
DisableGRPCConnectionLogs bool // Disables logging when a new grpc client has connected.
EnableFullSSZDataLogging bool // Enables logging for full ssz data on rejected gossip messages
@@ -256,9 +256,9 @@ func ConfigureBeaconChain(ctx *cli.Context) error {
logEnabled(EnableQUIC)
cfg.EnableQUIC = true
}
if ctx.IsSet(EnableCommitteeAwarePacking.Name) {
logEnabled(EnableCommitteeAwarePacking)
cfg.EnableCommitteeAwarePacking = true
if ctx.IsSet(DisableCommitteeAwarePacking.Name) {
logEnabled(DisableCommitteeAwarePacking)
cfg.DisableCommitteeAwarePacking = true
}
cfg.AggregateIntervals = [3]time.Duration{aggregateFirstInterval.Value, aggregateSecondInterval.Value, aggregateThirdInterval.Value}

View File

@@ -77,6 +77,12 @@ var (
Usage: deprecatedUsage,
Hidden: true,
}
deprecatedEnableCommitteeAwarePacking = &cli.BoolFlag{
Name: "enable-committee-aware-packing",
Usage: deprecatedUsage,
Hidden: true,
}
)
// Deprecated flags for both the beacon node and validator client.
@@ -94,6 +100,7 @@ var deprecatedFlags = []cli.Flag{
deprecatedBeaconRPCGatewayProviderFlag,
deprecatedDisableGRPCGateway,
deprecatedEnableExperimentalState,
deprecatedEnableCommitteeAwarePacking,
}
// deprecatedBeaconFlags contains flags that are still used by other components

View File

@@ -166,9 +166,9 @@ var (
Name: "enable-quic",
Usage: "Enables connection using the QUIC protocol for peers which support it.",
}
EnableCommitteeAwarePacking = &cli.BoolFlag{
Name: "enable-committee-aware-packing",
Usage: "Changes the attestation packing algorithm to one that is aware of attesting committees.",
DisableCommitteeAwarePacking = &cli.BoolFlag{
Name: "disable-committee-aware-packing",
Usage: "Changes the attestation packing algorithm to one that is not aware of attesting committees.",
}
)
@@ -226,7 +226,7 @@ var BeaconChainFlags = append(deprecatedBeaconFlags, append(deprecatedFlags, []c
EnableLightClient,
BlobSaveFsync,
EnableQUIC,
EnableCommitteeAwarePacking,
DisableCommitteeAwarePacking,
}...)...)
// E2EBeaconChainFlags contains a list of the beacon chain feature flags to be tested in E2E.

View File

@@ -33,7 +33,10 @@ const (
BlobSize = 131072 // defined to match blob.size in bazel ssz codegen
BlobSidecarSize = 131928 // defined to match blob sidecar size in bazel ssz codegen
KzgCommitmentInclusionProofDepth = 17 // Merkle proof depth for blob_kzg_commitments list item
NextSyncCommitteeBranchDepth = 5 // NextSyncCommitteeBranchDepth defines the depth of the next sync committee branch.
ExecutionBranchDepth = 4 // ExecutionBranchDepth defines the number of leaves in a merkle proof of the execution payload header.
SyncCommitteeBranchDepth = 5 // SyncCommitteeBranchDepth defines the number of leaves in a merkle proof of a sync committee.
SyncCommitteeBranchDepthElectra = 6 // SyncCommitteeBranchDepthElectra defines the number of leaves in a merkle proof of a sync committee.
FinalityBranchDepth = 6 // FinalityBranchDepth defines the number of leaves in a merkle proof of the finalized checkpoint root.
PendingBalanceDepositsLimit = 134217728 // Maximum number of pending balance deposits in the beacon state.
PendingPartialWithdrawalsLimit = 134217728 // Maximum number of pending partial withdrawals in the beacon state.
PendingConsolidationsLimit = 262144 // Maximum number of pending consolidations in the beacon state.

View File

@@ -33,7 +33,10 @@ const (
BlobSize = 131072 // defined to match blob.size in bazel ssz codegen
BlobSidecarSize = 131928 // defined to match blob sidecar size in bazel ssz codegen
KzgCommitmentInclusionProofDepth = 17 // Merkle proof depth for blob_kzg_commitments list item
NextSyncCommitteeBranchDepth = 5 // NextSyncCommitteeBranchDepth defines the depth of the next sync committee branch.
ExecutionBranchDepth = 4 // ExecutionBranchDepth defines the number of leaves in a merkle proof of the execution payload header.
SyncCommitteeBranchDepth = 5 // SyncCommitteeBranchDepth defines the number of leaves in a merkle proof of a sync committee.
SyncCommitteeBranchDepthElectra = 6 // SyncCommitteeBranchDepthElectra defines the number of leaves in a merkle proof of a sync committee.
FinalityBranchDepth = 6 // FinalityBranchDepth defines the number of leaves in a merkle proof of the finalized checkpoint root.
PendingBalanceDepositsLimit = 134217728 // Maximum number of pending balance deposits in the beacon state.
PendingPartialWithdrawalsLimit = 64 // Maximum number of pending partial withdrawals in the beacon state.
PendingConsolidationsLimit = 64 // Maximum number of pending consolidations in the beacon state.

View File

@@ -49,6 +49,7 @@ go_test(
"mainnet_config_test.go",
"testnet_config_test.go",
"testnet_holesky_config_test.go",
"testnet_sepolia_config_test.go",
],
data = glob(["*.yaml"]) + [
"testdata/e2e_config.yaml",
@@ -57,6 +58,7 @@ go_test(
"@consensus_spec_tests_minimal//:test_data",
"@eth2_networks//:configs",
"@holesky_testnet//:configs",
"@sepolia_testnet//:configs",
],
embed = [":go_default_library"],
gotags = ["develop"],

View File

@@ -11,11 +11,15 @@ func UseSepoliaNetworkConfig() {
cfg := BeaconNetworkConfig().Copy()
cfg.ContractDeploymentBlock = 1273020
cfg.BootstrapNodes = []string{
// EF boot nodes
"enr:-Ku4QDZ_rCowZFsozeWr60WwLgOfHzv1Fz2cuMvJqN5iJzLxKtVjoIURY42X_YTokMi3IGstW5v32uSYZyGUXj9Q_IECh2F0dG5ldHOIAAAAAAAAAACEZXRoMpCo_ujukAAAaf__________gmlkgnY0gmlwhIpEe5iJc2VjcDI1NmsxoQNHTpFdaNSCEWiN_QqT396nb0PzcUpLe3OVtLph-AciBYN1ZHCCIy0",
"enr:-Ku4QHRyRwEPT7s0XLYzJ_EeeWvZTXBQb4UCGy1F_3m-YtCNTtDlGsCMr4UTgo4uR89pv11uM-xq4w6GKfKhqU31hTgCh2F0dG5ldHOIAAAAAAAAAACEZXRoMpCo_ujukAAAaf__________gmlkgnY0gmlwhIrFM7WJc2VjcDI1NmsxoQI4diTwChN3zAAkarf7smOHCdFb1q3DSwdiQ_Lc_FdzFIN1ZHCCIy0",
"enr:-Ku4QOkvvf0u5Hg4-HhY-SJmEyft77G5h3rUM8VF_e-Hag5cAma3jtmFoX4WElLAqdILCA-UWFRN1ZCDJJVuEHrFeLkDh2F0dG5ldHOIAAAAAAAAAACEZXRoMpCo_ujukAAAaf__________gmlkgnY0gmlwhJK-AWeJc2VjcDI1NmsxoQLFcT5VE_NMiIC8Ll7GypWDnQ4UEmuzD7hF_Hf4veDJwIN1ZHCCIy0",
"enr:-Ku4QH6tYsHKITYeHUu5kdfXgEZWI18EWk_2RtGOn1jBPlx2UlS_uF3Pm5Dx7tnjOvla_zs-wwlPgjnEOcQDWXey51QCh2F0dG5ldHOIAAAAAAAAAACEZXRoMpCo_ujukAAAaf__________gmlkgnY0gmlwhIs7Mc6Jc2VjcDI1NmsxoQIET4Mlv9YzhrYhX_H9D7aWMemUrvki6W4J2Qo0YmFMp4N1ZHCCIy0",
"enr:-Ku4QDmz-4c1InchGitsgNk4qzorWMiFUoaPJT4G0IiF8r2UaevrekND1o7fdoftNucirj7sFFTTn2-JdC2Ej0p1Mn8Ch2F0dG5ldHOIAAAAAAAAAACEZXRoMpCo_ujukAAAaf__________gmlkgnY0gmlwhKpA-liJc2VjcDI1NmsxoQMpHP5U1DK8O_JQU6FadmWbE42qEdcGlllR8HcSkkfWq4N1ZHCCIy0",
"enr:-KO4QP7MmB3juk8rUjJHcUoxZDU9Np4FlW0HyDEGIjSO7GD9PbSsabu7713cWSUWKDkxIypIXg1A-6lG7ySRGOMZHeGCAmuEZXRoMpDTH2GRkAAAc___________gmlkgnY0gmlwhBSoyGOJc2VjcDI1NmsxoQNta5b_bexSSwwrGW2Re24MjfMntzFd0f2SAxQtMj3ueYN0Y3CCIyiDdWRwgiMo",
"enr:-KG4QJejf8KVtMeAPWFhN_P0c4efuwu1pZHELTveiXUeim6nKYcYcMIQpGxxdgT2Xp9h-M5pr9gn2NbbwEAtxzu50Y8BgmlkgnY0gmlwhEEVkQCDaXA2kCoBBPnAEJg4AAAAAAAAAAGJc2VjcDI1NmsxoQLEh_eVvk07AQABvLkTGBQTrrIOQkzouMgSBtNHIRUxOIN1ZHCCIyiEdWRwNoIjKA",
"enr:-Iq4QMCTfIMXnow27baRUb35Q8iiFHSIDBJh6hQM5Axohhf4b6Kr_cOCu0htQ5WvVqKvFgY28893DHAg8gnBAXsAVqmGAX53x8JggmlkgnY0gmlwhLKAlv6Jc2VjcDI1NmsxoQK6S-Cii_KmfFdUJL2TANL3ksaKUnNXvTCv1tLwXs0QgIN1ZHCCIyk",
"enr:-KG4QE5OIg5ThTjkzrlVF32WT_-XT14WeJtIz2zoTqLLjQhYAmJlnk4ItSoH41_2x0RX0wTFIe5GgjRzU2u7Q1fN4vADhGV0aDKQqP7o7pAAAHAyAAAAAAAAAIJpZIJ2NIJpcISlFsStiXNlY3AyNTZrMaEC-Rrd_bBZwhKpXzFCrStKp1q_HmGOewxY3KwM8ofAj_ODdGNwgiMog3VkcIIjKA",
// Teku boot node
"enr:-Ly4QFoZTWR8ulxGVsWydTNGdwEESueIdj-wB6UmmjUcm-AOPxnQi7wprzwcdo7-1jBW_JxELlUKJdJES8TDsbl1EdNlh2F0dG5ldHOI__78_v2bsV-EZXRoMpA2-lATkAAAcf__________gmlkgnY0gmlwhBLYJjGJc2VjcDI1NmsxoQI0gujXac9rMAb48NtMqtSTyHIeNYlpjkbYpWJw46PmYYhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA",
"enr:-L64QC9Hhov4DhQ7mRukTOz4_jHm4DHlGL726NWH4ojH1wFgEwSin_6H95Gs6nW2fktTWbPachHJ6rUFu0iJNgA0SB2CARqHYXR0bmV0c4j__________4RldGgykDb6UBOQAABx__________-CaWSCdjSCaXCEA-2vzolzZWNwMjU2azGhA17lsUg60R776rauYMdrAz383UUgESoaHEzMkvm4K6k6iHN5bmNuZXRzD4N0Y3CCIyiDdWRwgiMo",
}
OverrideBeaconNetworkConfig(cfg)
}

View File

@@ -0,0 +1,28 @@
package params_test
import (
"path"
"testing"
"github.com/bazelbuild/rules_go/go/tools/bazel"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/testing/require"
)
func TestSepoliaConfigMatchesUpstreamYaml(t *testing.T) {
presetFPs := presetsFilePath(t, "mainnet")
mn, err := params.ByName(params.MainnetName)
require.NoError(t, err)
cfg := mn.Copy()
for _, fp := range presetFPs {
cfg, err = params.UnmarshalConfigFile(fp, cfg)
require.NoError(t, err)
}
fPath, err := bazel.Runfile("external/sepolia_testnet")
require.NoError(t, err)
configFP := path.Join(fPath, "metadata", "config.yaml")
pcfg, err := params.UnmarshalConfigFile(configFP, nil)
require.NoError(t, err)
fields := fieldsFromYamls(t, append(presetFPs, configFP))
assertYamlFieldsMatch(t, "sepolia", fields, pcfg, params.SepoliaConfig())
}

View File

@@ -5,6 +5,7 @@ go_library(
srcs = [
"beacon_block.go",
"error.go",
"light_client.go",
"utils.go",
"validator.go",
],

View File

@@ -0,0 +1,58 @@
package interfaces
import (
ssz "github.com/prysmaticlabs/fastssz"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
pb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
)
type LightClientExecutionBranch = [fieldparams.ExecutionBranchDepth][fieldparams.RootLength]byte
type LightClientSyncCommitteeBranch = [fieldparams.SyncCommitteeBranchDepth][fieldparams.RootLength]byte
type LightClientFinalityBranch = [fieldparams.FinalityBranchDepth][fieldparams.RootLength]byte
type LightClientHeader interface {
ssz.Marshaler
Version() int
Beacon() *pb.BeaconBlockHeader
Execution() (ExecutionData, error)
ExecutionBranch() (LightClientExecutionBranch, error)
}
type LightClientBootstrap interface {
ssz.Marshaler
Version() int
Header() LightClientHeader
CurrentSyncCommittee() *pb.SyncCommittee
CurrentSyncCommitteeBranch() LightClientSyncCommitteeBranch
}
type LightClientUpdate interface {
ssz.Marshaler
Version() int
AttestedHeader() LightClientHeader
NextSyncCommittee() *pb.SyncCommittee
NextSyncCommitteeBranch() LightClientSyncCommitteeBranch
FinalizedHeader() LightClientHeader
FinalityBranch() LightClientFinalityBranch
SyncAggregate() *pb.SyncAggregate
SignatureSlot() primitives.Slot
}
type LightClientFinalityUpdate interface {
ssz.Marshaler
Version() int
AttestedHeader() LightClientHeader
FinalizedHeader() LightClientHeader
FinalityBranch() LightClientFinalityBranch
SyncAggregate() *pb.SyncAggregate
SignatureSlot() primitives.Slot
}
type LightClientOptimisticUpdate interface {
ssz.Marshaler
Version() int
AttestedHeader() LightClientHeader
SyncAggregate() *pb.SyncAggregate
SignatureSlot() primitives.Slot
}

View File

@@ -0,0 +1,26 @@
load("@prysm//tools/go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"bootstrap.go",
"finality_update.go",
"header.go",
"helpers.go",
"optimistic_update.go",
"update.go",
],
importpath = "github.com/prysmaticlabs/prysm/v5/consensus-types/light-client",
visibility = ["//visibility:public"],
deps = [
"//config/fieldparams:go_default_library",
"//consensus-types:go_default_library",
"//consensus-types/blocks:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//consensus-types/primitives:go_default_library",
"//encoding/bytesutil:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//runtime/version:go_default_library",
"@org_golang_google_protobuf//proto:go_default_library",
],
)

View File

@@ -0,0 +1,208 @@
package light_client
import (
"fmt"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
consensustypes "github.com/prysmaticlabs/prysm/v5/consensus-types"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
pb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"google.golang.org/protobuf/proto"
)
func NewWrappedBootstrap(m proto.Message) (interfaces.LightClientBootstrap, error) {
if m == nil {
return nil, consensustypes.ErrNilObjectWrapped
}
switch t := m.(type) {
case *pb.LightClientBootstrapAltair:
return NewWrappedBootstrapAltair(t)
case *pb.LightClientBootstrapCapella:
return NewWrappedBootstrapCapella(t)
case *pb.LightClientBootstrapDeneb:
return NewWrappedBootstrapDeneb(t)
default:
return nil, fmt.Errorf("cannot construct light client bootstrap from type %T", t)
}
}
type bootstrapAltair struct {
p *pb.LightClientBootstrapAltair
header interfaces.LightClientHeader
currentSyncCommitteeBranch interfaces.LightClientSyncCommitteeBranch
}
var _ interfaces.LightClientBootstrap = &bootstrapAltair{}
func NewWrappedBootstrapAltair(p *pb.LightClientBootstrapAltair) (interfaces.LightClientBootstrap, error) {
if p == nil {
return nil, consensustypes.ErrNilObjectWrapped
}
header, err := NewWrappedHeaderAltair(p.Header)
if err != nil {
return nil, err
}
branch, err := createBranch[interfaces.LightClientSyncCommitteeBranch](
"sync committee",
p.CurrentSyncCommitteeBranch,
fieldparams.SyncCommitteeBranchDepth,
)
if err != nil {
return nil, err
}
return &bootstrapAltair{
p: p,
header: header,
currentSyncCommitteeBranch: branch,
}, nil
}
func (h *bootstrapAltair) MarshalSSZTo(dst []byte) ([]byte, error) {
return h.p.MarshalSSZTo(dst)
}
func (h *bootstrapAltair) MarshalSSZ() ([]byte, error) {
return h.p.MarshalSSZ()
}
func (h *bootstrapAltair) SizeSSZ() int {
return h.p.SizeSSZ()
}
func (h *bootstrapAltair) Version() int {
return version.Altair
}
func (h *bootstrapAltair) Header() interfaces.LightClientHeader {
return h.header
}
func (h *bootstrapAltair) CurrentSyncCommittee() *pb.SyncCommittee {
return h.p.CurrentSyncCommittee
}
func (h *bootstrapAltair) CurrentSyncCommitteeBranch() interfaces.LightClientSyncCommitteeBranch {
return h.currentSyncCommitteeBranch
}
type bootstrapCapella struct {
p *pb.LightClientBootstrapCapella
header interfaces.LightClientHeader
currentSyncCommitteeBranch interfaces.LightClientSyncCommitteeBranch
}
var _ interfaces.LightClientBootstrap = &bootstrapCapella{}
func NewWrappedBootstrapCapella(p *pb.LightClientBootstrapCapella) (interfaces.LightClientBootstrap, error) {
if p == nil {
return nil, consensustypes.ErrNilObjectWrapped
}
header, err := NewWrappedHeaderCapella(p.Header)
if err != nil {
return nil, err
}
branch, err := createBranch[interfaces.LightClientSyncCommitteeBranch](
"sync committee",
p.CurrentSyncCommitteeBranch,
fieldparams.SyncCommitteeBranchDepth,
)
if err != nil {
return nil, err
}
return &bootstrapCapella{
p: p,
header: header,
currentSyncCommitteeBranch: branch,
}, nil
}
func (h *bootstrapCapella) MarshalSSZTo(dst []byte) ([]byte, error) {
return h.p.MarshalSSZTo(dst)
}
func (h *bootstrapCapella) MarshalSSZ() ([]byte, error) {
return h.p.MarshalSSZ()
}
func (h *bootstrapCapella) SizeSSZ() int {
return h.p.SizeSSZ()
}
func (h *bootstrapCapella) Version() int {
return version.Capella
}
func (h *bootstrapCapella) Header() interfaces.LightClientHeader {
return h.header
}
func (h *bootstrapCapella) CurrentSyncCommittee() *pb.SyncCommittee {
return h.p.CurrentSyncCommittee
}
func (h *bootstrapCapella) CurrentSyncCommitteeBranch() interfaces.LightClientSyncCommitteeBranch {
return h.currentSyncCommitteeBranch
}
type bootstrapDeneb struct {
p *pb.LightClientBootstrapDeneb
header interfaces.LightClientHeader
currentSyncCommitteeBranch interfaces.LightClientSyncCommitteeBranch
}
var _ interfaces.LightClientBootstrap = &bootstrapDeneb{}
func NewWrappedBootstrapDeneb(p *pb.LightClientBootstrapDeneb) (interfaces.LightClientBootstrap, error) {
if p == nil {
return nil, consensustypes.ErrNilObjectWrapped
}
header, err := NewWrappedHeaderDeneb(p.Header)
if err != nil {
return nil, err
}
branch, err := createBranch[interfaces.LightClientSyncCommitteeBranch](
"sync committee",
p.CurrentSyncCommitteeBranch,
fieldparams.SyncCommitteeBranchDepth,
)
if err != nil {
return nil, err
}
return &bootstrapDeneb{
p: p,
header: header,
currentSyncCommitteeBranch: branch,
}, nil
}
func (h *bootstrapDeneb) MarshalSSZTo(dst []byte) ([]byte, error) {
return h.p.MarshalSSZTo(dst)
}
func (h *bootstrapDeneb) MarshalSSZ() ([]byte, error) {
return h.p.MarshalSSZ()
}
func (h *bootstrapDeneb) SizeSSZ() int {
return h.p.SizeSSZ()
}
func (h *bootstrapDeneb) Version() int {
return version.Deneb
}
func (h *bootstrapDeneb) Header() interfaces.LightClientHeader {
return h.header
}
func (h *bootstrapDeneb) CurrentSyncCommittee() *pb.SyncCommittee {
return h.p.CurrentSyncCommittee
}
func (h *bootstrapDeneb) CurrentSyncCommitteeBranch() interfaces.LightClientSyncCommitteeBranch {
return h.currentSyncCommitteeBranch
}

View File

@@ -0,0 +1,251 @@
package light_client
import (
"fmt"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
consensustypes "github.com/prysmaticlabs/prysm/v5/consensus-types"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
pb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"google.golang.org/protobuf/proto"
)
func NewWrappedFinalityUpdate(m proto.Message) (interfaces.LightClientFinalityUpdate, error) {
if m == nil {
return nil, consensustypes.ErrNilObjectWrapped
}
switch t := m.(type) {
case *pb.LightClientFinalityUpdateAltair:
return NewWrappedFinalityUpdateAltair(t)
case *pb.LightClientFinalityUpdateCapella:
return NewWrappedFinalityUpdateCapella(t)
case *pb.LightClientFinalityUpdateDeneb:
return NewWrappedFinalityUpdateDeneb(t)
default:
return nil, fmt.Errorf("cannot construct light client finality update from type %T", t)
}
}
type finalityUpdateAltair struct {
p *pb.LightClientFinalityUpdateAltair
attestedHeader interfaces.LightClientHeader
finalizedHeader interfaces.LightClientHeader
finalityBranch interfaces.LightClientFinalityBranch
}
var _ interfaces.LightClientFinalityUpdate = &finalityUpdateAltair{}
func NewWrappedFinalityUpdateAltair(p *pb.LightClientFinalityUpdateAltair) (interfaces.LightClientFinalityUpdate, error) {
if p == nil {
return nil, consensustypes.ErrNilObjectWrapped
}
attestedHeader, err := NewWrappedHeaderAltair(p.AttestedHeader)
if err != nil {
return nil, err
}
finalizedHeader, err := NewWrappedHeaderAltair(p.FinalizedHeader)
if err != nil {
return nil, err
}
branch, err := createBranch[interfaces.LightClientFinalityBranch](
"finality",
p.FinalityBranch,
fieldparams.FinalityBranchDepth,
)
if err != nil {
return nil, err
}
return &finalityUpdateAltair{
p: p,
attestedHeader: attestedHeader,
finalizedHeader: finalizedHeader,
finalityBranch: branch,
}, nil
}
func (u *finalityUpdateAltair) MarshalSSZTo(dst []byte) ([]byte, error) {
return u.p.MarshalSSZTo(dst)
}
func (u *finalityUpdateAltair) MarshalSSZ() ([]byte, error) {
return u.p.MarshalSSZ()
}
func (u *finalityUpdateAltair) SizeSSZ() int {
return u.p.SizeSSZ()
}
func (u *finalityUpdateAltair) Version() int {
return version.Altair
}
func (u *finalityUpdateAltair) AttestedHeader() interfaces.LightClientHeader {
return u.attestedHeader
}
func (u *finalityUpdateAltair) FinalizedHeader() interfaces.LightClientHeader {
return u.finalizedHeader
}
func (u *finalityUpdateAltair) FinalityBranch() interfaces.LightClientFinalityBranch {
return u.finalityBranch
}
func (u *finalityUpdateAltair) SyncAggregate() *pb.SyncAggregate {
return u.p.SyncAggregate
}
func (u *finalityUpdateAltair) SignatureSlot() primitives.Slot {
return u.p.SignatureSlot
}
type finalityUpdateCapella struct {
p *pb.LightClientFinalityUpdateCapella
attestedHeader interfaces.LightClientHeader
finalizedHeader interfaces.LightClientHeader
finalityBranch interfaces.LightClientFinalityBranch
}
var _ interfaces.LightClientFinalityUpdate = &finalityUpdateCapella{}
func NewWrappedFinalityUpdateCapella(p *pb.LightClientFinalityUpdateCapella) (interfaces.LightClientFinalityUpdate, error) {
if p == nil {
return nil, consensustypes.ErrNilObjectWrapped
}
attestedHeader, err := NewWrappedHeaderCapella(p.AttestedHeader)
if err != nil {
return nil, err
}
finalizedHeader, err := NewWrappedHeaderCapella(p.FinalizedHeader)
if err != nil {
return nil, err
}
branch, err := createBranch[interfaces.LightClientFinalityBranch](
"finality",
p.FinalityBranch,
fieldparams.FinalityBranchDepth,
)
if err != nil {
return nil, err
}
return &finalityUpdateCapella{
p: p,
attestedHeader: attestedHeader,
finalizedHeader: finalizedHeader,
finalityBranch: branch,
}, nil
}
func (u *finalityUpdateCapella) MarshalSSZTo(dst []byte) ([]byte, error) {
return u.p.MarshalSSZTo(dst)
}
func (u *finalityUpdateCapella) MarshalSSZ() ([]byte, error) {
return u.p.MarshalSSZ()
}
func (u *finalityUpdateCapella) SizeSSZ() int {
return u.p.SizeSSZ()
}
func (u *finalityUpdateCapella) Version() int {
return version.Capella
}
func (u *finalityUpdateCapella) AttestedHeader() interfaces.LightClientHeader {
return u.attestedHeader
}
func (u *finalityUpdateCapella) FinalizedHeader() interfaces.LightClientHeader {
return u.finalizedHeader
}
func (u *finalityUpdateCapella) FinalityBranch() interfaces.LightClientFinalityBranch {
return u.finalityBranch
}
func (u *finalityUpdateCapella) SyncAggregate() *pb.SyncAggregate {
return u.p.SyncAggregate
}
func (u *finalityUpdateCapella) SignatureSlot() primitives.Slot {
return u.p.SignatureSlot
}
type finalityUpdateDeneb struct {
p *pb.LightClientFinalityUpdateDeneb
attestedHeader interfaces.LightClientHeader
finalizedHeader interfaces.LightClientHeader
finalityBranch interfaces.LightClientFinalityBranch
}
var _ interfaces.LightClientFinalityUpdate = &finalityUpdateDeneb{}
func NewWrappedFinalityUpdateDeneb(p *pb.LightClientFinalityUpdateDeneb) (interfaces.LightClientFinalityUpdate, error) {
if p == nil {
return nil, consensustypes.ErrNilObjectWrapped
}
attestedHeader, err := NewWrappedHeaderDeneb(p.AttestedHeader)
if err != nil {
return nil, err
}
finalizedHeader, err := NewWrappedHeaderDeneb(p.FinalizedHeader)
if err != nil {
return nil, err
}
branch, err := createBranch[interfaces.LightClientFinalityBranch](
"finality",
p.FinalityBranch,
fieldparams.FinalityBranchDepth,
)
if err != nil {
return nil, err
}
return &finalityUpdateDeneb{
p: p,
attestedHeader: attestedHeader,
finalizedHeader: finalizedHeader,
finalityBranch: branch,
}, nil
}
func (u *finalityUpdateDeneb) MarshalSSZTo(dst []byte) ([]byte, error) {
return u.p.MarshalSSZTo(dst)
}
func (u *finalityUpdateDeneb) MarshalSSZ() ([]byte, error) {
return u.p.MarshalSSZ()
}
func (u *finalityUpdateDeneb) SizeSSZ() int {
return u.p.SizeSSZ()
}
func (u *finalityUpdateDeneb) Version() int {
return version.Deneb
}
func (u *finalityUpdateDeneb) AttestedHeader() interfaces.LightClientHeader {
return u.attestedHeader
}
func (u *finalityUpdateDeneb) FinalizedHeader() interfaces.LightClientHeader {
return u.finalizedHeader
}
func (u *finalityUpdateDeneb) FinalityBranch() interfaces.LightClientFinalityBranch {
return u.finalityBranch
}
func (u *finalityUpdateDeneb) SyncAggregate() *pb.SyncAggregate {
return u.p.SyncAggregate
}
func (u *finalityUpdateDeneb) SignatureSlot() primitives.Slot {
return u.p.SignatureSlot
}

View File

@@ -0,0 +1,192 @@
package light_client
import (
"fmt"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
consensustypes "github.com/prysmaticlabs/prysm/v5/consensus-types"
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
pb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"google.golang.org/protobuf/proto"
)
func NewWrappedHeader(m proto.Message) (interfaces.LightClientHeader, error) {
if m == nil {
return nil, consensustypes.ErrNilObjectWrapped
}
switch t := m.(type) {
case *pb.LightClientHeaderAltair:
return NewWrappedHeaderAltair(t)
case *pb.LightClientHeaderCapella:
return NewWrappedHeaderCapella(t)
case *pb.LightClientHeaderDeneb:
return NewWrappedHeaderDeneb(t)
default:
return nil, fmt.Errorf("cannot construct light client header from type %T", t)
}
}
type headerAltair struct {
p *pb.LightClientHeaderAltair
}
var _ interfaces.LightClientHeader = &headerAltair{}
func NewWrappedHeaderAltair(p *pb.LightClientHeaderAltair) (interfaces.LightClientHeader, error) {
if p == nil {
return nil, consensustypes.ErrNilObjectWrapped
}
return &headerAltair{p: p}, nil
}
func (h *headerAltair) MarshalSSZTo(dst []byte) ([]byte, error) {
return h.p.MarshalSSZTo(dst)
}
func (h *headerAltair) MarshalSSZ() ([]byte, error) {
return h.p.MarshalSSZ()
}
func (h *headerAltair) SizeSSZ() int {
return h.p.SizeSSZ()
}
func (h *headerAltair) Version() int {
return version.Altair
}
func (h *headerAltair) Beacon() *pb.BeaconBlockHeader {
return h.p.Beacon
}
func (h *headerAltair) Execution() (interfaces.ExecutionData, error) {
return nil, consensustypes.ErrNotSupported("Execution", version.Altair)
}
func (h *headerAltair) ExecutionBranch() (interfaces.LightClientExecutionBranch, error) {
return interfaces.LightClientExecutionBranch{}, consensustypes.ErrNotSupported("ExecutionBranch", version.Altair)
}
type headerCapella struct {
p *pb.LightClientHeaderCapella
execution interfaces.ExecutionData
executionBranch interfaces.LightClientExecutionBranch
}
var _ interfaces.LightClientHeader = &headerCapella{}
func NewWrappedHeaderCapella(p *pb.LightClientHeaderCapella) (interfaces.LightClientHeader, error) {
if p == nil {
return nil, consensustypes.ErrNilObjectWrapped
}
execution, err := blocks.WrappedExecutionPayloadHeaderCapella(p.Execution)
if err != nil {
return nil, err
}
branch, err := createBranch[interfaces.LightClientExecutionBranch](
"execution",
p.ExecutionBranch,
fieldparams.ExecutionBranchDepth,
)
if err != nil {
return nil, err
}
return &headerCapella{
p: p,
execution: execution,
executionBranch: branch,
}, nil
}
func (h *headerCapella) MarshalSSZTo(dst []byte) ([]byte, error) {
return h.p.MarshalSSZTo(dst)
}
func (h *headerCapella) MarshalSSZ() ([]byte, error) {
return h.p.MarshalSSZ()
}
func (h *headerCapella) SizeSSZ() int {
return h.p.SizeSSZ()
}
func (h *headerCapella) Version() int {
return version.Capella
}
func (h *headerCapella) Beacon() *pb.BeaconBlockHeader {
return h.p.Beacon
}
func (h *headerCapella) Execution() (interfaces.ExecutionData, error) {
return h.execution, nil
}
func (h *headerCapella) ExecutionBranch() (interfaces.LightClientExecutionBranch, error) {
return h.executionBranch, nil
}
type headerDeneb struct {
p *pb.LightClientHeaderDeneb
execution interfaces.ExecutionData
executionBranch interfaces.LightClientExecutionBranch
}
var _ interfaces.LightClientHeader = &headerDeneb{}
func NewWrappedHeaderDeneb(p *pb.LightClientHeaderDeneb) (interfaces.LightClientHeader, error) {
if p == nil {
return nil, consensustypes.ErrNilObjectWrapped
}
execution, err := blocks.WrappedExecutionPayloadHeaderDeneb(p.Execution)
if err != nil {
return nil, err
}
branch, err := createBranch[interfaces.LightClientExecutionBranch](
"execution",
p.ExecutionBranch,
fieldparams.ExecutionBranchDepth,
)
if err != nil {
return nil, err
}
return &headerDeneb{
p: p,
execution: execution,
executionBranch: branch,
}, nil
}
func (h *headerDeneb) MarshalSSZTo(dst []byte) ([]byte, error) {
return h.p.MarshalSSZTo(dst)
}
func (h *headerDeneb) MarshalSSZ() ([]byte, error) {
return h.p.MarshalSSZ()
}
func (h *headerDeneb) SizeSSZ() int {
return h.p.SizeSSZ()
}
func (h *headerDeneb) Version() int {
return version.Deneb
}
func (h *headerDeneb) Beacon() *pb.BeaconBlockHeader {
return h.p.Beacon
}
func (h *headerDeneb) Execution() (interfaces.ExecutionData, error) {
return h.execution, nil
}
func (h *headerDeneb) ExecutionBranch() (interfaces.LightClientExecutionBranch, error) {
return h.executionBranch, nil
}

View File

@@ -0,0 +1,30 @@
package light_client
import (
"fmt"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
)
type branchConstraint interface {
~interfaces.LightClientExecutionBranch | ~interfaces.LightClientSyncCommitteeBranch | ~interfaces.LightClientFinalityBranch
}
func createBranch[T branchConstraint](name string, input [][]byte, depth int) (T, error) {
var zero T
if len(input) != depth {
return zero, fmt.Errorf("%s branch has %d leaves instead of expected %d", name, len(input), depth)
}
var branch T
for i, leaf := range input {
if len(leaf) != fieldparams.RootLength {
return zero, fmt.Errorf("%s branch leaf at index %d has length %d instead of expected %d", name, i, len(leaf), fieldparams.RootLength)
}
branch[i] = bytesutil.ToBytes32(leaf)
}
return branch, nil
}

View File

@@ -0,0 +1,178 @@
package light_client
import (
"fmt"
consensustypes "github.com/prysmaticlabs/prysm/v5/consensus-types"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
pb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"google.golang.org/protobuf/proto"
)
func NewWrappedOptimisticUpdate(m proto.Message) (interfaces.LightClientOptimisticUpdate, error) {
if m == nil {
return nil, consensustypes.ErrNilObjectWrapped
}
switch t := m.(type) {
case *pb.LightClientOptimisticUpdateAltair:
return NewWrappedOptimisticUpdateAltair(t)
case *pb.LightClientOptimisticUpdateCapella:
return NewWrappedOptimisticUpdateCapella(t)
case *pb.LightClientOptimisticUpdateDeneb:
return NewWrappedOptimisticUpdateDeneb(t)
default:
return nil, fmt.Errorf("cannot construct light client optimistic update from type %T", t)
}
}
type OptimisticUpdateAltair struct {
p *pb.LightClientOptimisticUpdateAltair
attestedHeader interfaces.LightClientHeader
}
var _ interfaces.LightClientOptimisticUpdate = &OptimisticUpdateAltair{}
func NewWrappedOptimisticUpdateAltair(p *pb.LightClientOptimisticUpdateAltair) (interfaces.LightClientOptimisticUpdate, error) {
if p == nil {
return nil, consensustypes.ErrNilObjectWrapped
}
attestedHeader, err := NewWrappedHeaderAltair(p.AttestedHeader)
if err != nil {
return nil, err
}
return &OptimisticUpdateAltair{
p: p,
attestedHeader: attestedHeader,
}, nil
}
func (u *OptimisticUpdateAltair) MarshalSSZTo(dst []byte) ([]byte, error) {
return u.p.MarshalSSZTo(dst)
}
func (u *OptimisticUpdateAltair) MarshalSSZ() ([]byte, error) {
return u.p.MarshalSSZ()
}
func (u *OptimisticUpdateAltair) SizeSSZ() int {
return u.p.SizeSSZ()
}
func (u *OptimisticUpdateAltair) Version() int {
return version.Altair
}
func (u *OptimisticUpdateAltair) AttestedHeader() interfaces.LightClientHeader {
return u.attestedHeader
}
func (u *OptimisticUpdateAltair) SyncAggregate() *pb.SyncAggregate {
return u.p.SyncAggregate
}
func (u *OptimisticUpdateAltair) SignatureSlot() primitives.Slot {
return u.p.SignatureSlot
}
type OptimisticUpdateCapella struct {
p *pb.LightClientOptimisticUpdateCapella
attestedHeader interfaces.LightClientHeader
}
var _ interfaces.LightClientOptimisticUpdate = &OptimisticUpdateCapella{}
func NewWrappedOptimisticUpdateCapella(p *pb.LightClientOptimisticUpdateCapella) (interfaces.LightClientOptimisticUpdate, error) {
if p == nil {
return nil, consensustypes.ErrNilObjectWrapped
}
attestedHeader, err := NewWrappedHeaderCapella(p.AttestedHeader)
if err != nil {
return nil, err
}
return &OptimisticUpdateCapella{
p: p,
attestedHeader: attestedHeader,
}, nil
}
func (u *OptimisticUpdateCapella) MarshalSSZTo(dst []byte) ([]byte, error) {
return u.p.MarshalSSZTo(dst)
}
func (u *OptimisticUpdateCapella) MarshalSSZ() ([]byte, error) {
return u.p.MarshalSSZ()
}
func (u *OptimisticUpdateCapella) SizeSSZ() int {
return u.p.SizeSSZ()
}
func (u *OptimisticUpdateCapella) Version() int {
return version.Capella
}
func (u *OptimisticUpdateCapella) AttestedHeader() interfaces.LightClientHeader {
return u.attestedHeader
}
func (u *OptimisticUpdateCapella) SyncAggregate() *pb.SyncAggregate {
return u.p.SyncAggregate
}
func (u *OptimisticUpdateCapella) SignatureSlot() primitives.Slot {
return u.p.SignatureSlot
}
type OptimisticUpdateDeneb struct {
p *pb.LightClientOptimisticUpdateDeneb
attestedHeader interfaces.LightClientHeader
}
var _ interfaces.LightClientOptimisticUpdate = &OptimisticUpdateDeneb{}
func NewWrappedOptimisticUpdateDeneb(p *pb.LightClientOptimisticUpdateDeneb) (interfaces.LightClientOptimisticUpdate, error) {
if p == nil {
return nil, consensustypes.ErrNilObjectWrapped
}
attestedHeader, err := NewWrappedHeaderDeneb(p.AttestedHeader)
if err != nil {
return nil, err
}
return &OptimisticUpdateDeneb{
p: p,
attestedHeader: attestedHeader,
}, nil
}
func (u *OptimisticUpdateDeneb) MarshalSSZTo(dst []byte) ([]byte, error) {
return u.p.MarshalSSZTo(dst)
}
func (u *OptimisticUpdateDeneb) MarshalSSZ() ([]byte, error) {
return u.p.MarshalSSZ()
}
func (u *OptimisticUpdateDeneb) SizeSSZ() int {
return u.p.SizeSSZ()
}
func (u *OptimisticUpdateDeneb) Version() int {
return version.Deneb
}
func (u *OptimisticUpdateDeneb) AttestedHeader() interfaces.LightClientHeader {
return u.attestedHeader
}
func (u *OptimisticUpdateDeneb) SyncAggregate() *pb.SyncAggregate {
return u.p.SyncAggregate
}
func (u *OptimisticUpdateDeneb) SignatureSlot() primitives.Slot {
return u.p.SignatureSlot
}

View File

@@ -0,0 +1,305 @@
package light_client
import (
"fmt"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
consensustypes "github.com/prysmaticlabs/prysm/v5/consensus-types"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
pb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"google.golang.org/protobuf/proto"
)
func NewWrappedUpdate(m proto.Message) (interfaces.LightClientUpdate, error) {
if m == nil {
return nil, consensustypes.ErrNilObjectWrapped
}
switch t := m.(type) {
case *pb.LightClientUpdateAltair:
return NewWrappedUpdateAltair(t)
case *pb.LightClientUpdateCapella:
return NewWrappedUpdateCapella(t)
case *pb.LightClientUpdateDeneb:
return NewWrappedUpdateDeneb(t)
default:
return nil, fmt.Errorf("cannot construct light client update from type %T", t)
}
}
type updateAltair struct {
p *pb.LightClientUpdateAltair
attestedHeader interfaces.LightClientHeader
nextSyncCommitteeBranch interfaces.LightClientSyncCommitteeBranch
finalizedHeader interfaces.LightClientHeader
finalityBranch interfaces.LightClientFinalityBranch
}
var _ interfaces.LightClientUpdate = &updateAltair{}
func NewWrappedUpdateAltair(p *pb.LightClientUpdateAltair) (interfaces.LightClientUpdate, error) {
if p == nil {
return nil, consensustypes.ErrNilObjectWrapped
}
attestedHeader, err := NewWrappedHeaderAltair(p.AttestedHeader)
if err != nil {
return nil, err
}
finalizedHeader, err := NewWrappedHeaderAltair(p.FinalizedHeader)
if err != nil {
return nil, err
}
scBranch, err := createBranch[interfaces.LightClientSyncCommitteeBranch](
"sync committee",
p.NextSyncCommitteeBranch,
fieldparams.SyncCommitteeBranchDepth,
)
if err != nil {
return nil, err
}
finalityBranch, err := createBranch[interfaces.LightClientFinalityBranch](
"finality",
p.FinalityBranch,
fieldparams.FinalityBranchDepth,
)
if err != nil {
return nil, err
}
return &updateAltair{
p: p,
attestedHeader: attestedHeader,
nextSyncCommitteeBranch: scBranch,
finalizedHeader: finalizedHeader,
finalityBranch: finalityBranch,
}, nil
}
func (u *updateAltair) MarshalSSZTo(dst []byte) ([]byte, error) {
return u.p.MarshalSSZTo(dst)
}
func (u *updateAltair) MarshalSSZ() ([]byte, error) {
return u.p.MarshalSSZ()
}
func (u *updateAltair) SizeSSZ() int {
return u.p.SizeSSZ()
}
func (u *updateAltair) Version() int {
return version.Altair
}
func (u *updateAltair) AttestedHeader() interfaces.LightClientHeader {
return u.attestedHeader
}
func (u *updateAltair) NextSyncCommittee() *pb.SyncCommittee {
return u.p.NextSyncCommittee
}
func (u *updateAltair) NextSyncCommitteeBranch() interfaces.LightClientSyncCommitteeBranch {
return u.nextSyncCommitteeBranch
}
func (u *updateAltair) FinalizedHeader() interfaces.LightClientHeader {
return u.finalizedHeader
}
func (u *updateAltair) FinalityBranch() interfaces.LightClientFinalityBranch {
return u.finalityBranch
}
func (u *updateAltair) SyncAggregate() *pb.SyncAggregate {
return u.p.SyncAggregate
}
func (u *updateAltair) SignatureSlot() primitives.Slot {
return u.p.SignatureSlot
}
type updateCapella struct {
p *pb.LightClientUpdateCapella
attestedHeader interfaces.LightClientHeader
nextSyncCommitteeBranch interfaces.LightClientSyncCommitteeBranch
finalizedHeader interfaces.LightClientHeader
finalityBranch interfaces.LightClientFinalityBranch
}
var _ interfaces.LightClientUpdate = &updateCapella{}
func NewWrappedUpdateCapella(p *pb.LightClientUpdateCapella) (interfaces.LightClientUpdate, error) {
if p == nil {
return nil, consensustypes.ErrNilObjectWrapped
}
attestedHeader, err := NewWrappedHeaderCapella(p.AttestedHeader)
if err != nil {
return nil, err
}
finalizedHeader, err := NewWrappedHeaderCapella(p.FinalizedHeader)
if err != nil {
return nil, err
}
scBranch, err := createBranch[interfaces.LightClientSyncCommitteeBranch](
"sync committee",
p.NextSyncCommitteeBranch,
fieldparams.SyncCommitteeBranchDepth,
)
if err != nil {
return nil, err
}
finalityBranch, err := createBranch[interfaces.LightClientFinalityBranch](
"finality",
p.FinalityBranch,
fieldparams.FinalityBranchDepth,
)
if err != nil {
return nil, err
}
return &updateCapella{
p: p,
attestedHeader: attestedHeader,
nextSyncCommitteeBranch: scBranch,
finalizedHeader: finalizedHeader,
finalityBranch: finalityBranch,
}, nil
}
func (u *updateCapella) MarshalSSZTo(dst []byte) ([]byte, error) {
return u.p.MarshalSSZTo(dst)
}
func (u *updateCapella) MarshalSSZ() ([]byte, error) {
return u.p.MarshalSSZ()
}
func (u *updateCapella) SizeSSZ() int {
return u.p.SizeSSZ()
}
func (u *updateCapella) Version() int {
return version.Capella
}
func (u *updateCapella) AttestedHeader() interfaces.LightClientHeader {
return u.attestedHeader
}
func (u *updateCapella) NextSyncCommittee() *pb.SyncCommittee {
return u.p.NextSyncCommittee
}
func (u *updateCapella) NextSyncCommitteeBranch() interfaces.LightClientSyncCommitteeBranch {
return u.nextSyncCommitteeBranch
}
func (u *updateCapella) FinalizedHeader() interfaces.LightClientHeader {
return u.finalizedHeader
}
func (u *updateCapella) FinalityBranch() interfaces.LightClientFinalityBranch {
return u.finalityBranch
}
func (u *updateCapella) SyncAggregate() *pb.SyncAggregate {
return u.p.SyncAggregate
}
func (u *updateCapella) SignatureSlot() primitives.Slot {
return u.p.SignatureSlot
}
type updateDeneb struct {
p *pb.LightClientUpdateDeneb
attestedHeader interfaces.LightClientHeader
nextSyncCommitteeBranch interfaces.LightClientSyncCommitteeBranch
finalizedHeader interfaces.LightClientHeader
finalityBranch interfaces.LightClientFinalityBranch
}
var _ interfaces.LightClientUpdate = &updateDeneb{}
func NewWrappedUpdateDeneb(p *pb.LightClientUpdateDeneb) (interfaces.LightClientUpdate, error) {
if p == nil {
return nil, consensustypes.ErrNilObjectWrapped
}
attestedHeader, err := NewWrappedHeaderDeneb(p.AttestedHeader)
if err != nil {
return nil, err
}
finalizedHeader, err := NewWrappedHeaderDeneb(p.FinalizedHeader)
if err != nil {
return nil, err
}
scBranch, err := createBranch[interfaces.LightClientSyncCommitteeBranch](
"sync committee",
p.NextSyncCommitteeBranch,
fieldparams.SyncCommitteeBranchDepth,
)
if err != nil {
return nil, err
}
finalityBranch, err := createBranch[interfaces.LightClientFinalityBranch](
"finality",
p.FinalityBranch,
fieldparams.FinalityBranchDepth,
)
if err != nil {
return nil, err
}
return &updateDeneb{
p: p,
attestedHeader: attestedHeader,
nextSyncCommitteeBranch: scBranch,
finalizedHeader: finalizedHeader,
finalityBranch: finalityBranch,
}, nil
}
func (u *updateDeneb) MarshalSSZTo(dst []byte) ([]byte, error) {
return u.p.MarshalSSZTo(dst)
}
func (u *updateDeneb) MarshalSSZ() ([]byte, error) {
return u.p.MarshalSSZ()
}
func (u *updateDeneb) SizeSSZ() int {
return u.p.SizeSSZ()
}
func (u *updateDeneb) Version() int {
return version.Deneb
}
func (u *updateDeneb) AttestedHeader() interfaces.LightClientHeader {
return u.attestedHeader
}
func (u *updateDeneb) NextSyncCommittee() *pb.SyncCommittee {
return u.p.NextSyncCommittee
}
func (u *updateDeneb) NextSyncCommitteeBranch() interfaces.LightClientSyncCommitteeBranch {
return u.nextSyncCommitteeBranch
}
func (u *updateDeneb) FinalizedHeader() interfaces.LightClientHeader {
return u.finalizedHeader
}
func (u *updateDeneb) FinalityBranch() interfaces.LightClientFinalityBranch {
return u.finalityBranch
}
func (u *updateDeneb) SyncAggregate() *pb.SyncAggregate {
return u.p.SyncAggregate
}
func (u *updateDeneb) SignatureSlot() primitives.Slot {
return u.p.SignatureSlot
}

View File

@@ -9,6 +9,7 @@ go_library(
"domain.go",
"epoch.go",
"execution_address.go",
"kzg.go",
"payload_id.go",
"randao.go",
"slot.go",
@@ -21,6 +22,7 @@ go_library(
visibility = ["//visibility:public"],
deps = [
"//math:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_prysmaticlabs_fastssz//:go_default_library",
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
],

View File

@@ -0,0 +1,15 @@
package primitives
import (
"crypto/sha256"
"github.com/ethereum/go-ethereum/common"
)
const blobCommitmentVersionKZG uint8 = 0x01
func ConvertKzgCommitmentToVersionedHash(commitment []byte) common.Hash {
versionedHash := sha256.Sum256(commitment)
versionedHash[0] = blobCommitmentVersionKZG
return versionedHash
}

View File

@@ -2781,8 +2781,8 @@ def prysm_deps():
go_repository(
name = "com_github_prysmaticlabs_fastssz",
importpath = "github.com/prysmaticlabs/fastssz",
sum = "h1:0LZAwwHnsZFfXm4IK4rzFV4N5IVSKZKLmuBMA4kAlFk=",
version = "v0.0.0-20240620202422-a981b8ef89d3",
sum = "h1:xuVAdtz5ShYblG2sPyb4gw01DF8InbOI/kBCQjk7NiM=",
version = "v0.0.0-20241008181541-518c4ce73516",
)
go_repository(
name = "com_github_prysmaticlabs_go_bitfield",
@@ -2833,6 +2833,12 @@ def prysm_deps():
sum = "h1:HxSrwun11U+LlmwpgM1kEqIqH90IT4N8auv/cD7QFJg=",
version = "v0.8.0",
)
go_repository(
name = "com_github_r3labs_sse_v2",
importpath = "github.com/r3labs/sse/v2",
sum = "h1:hFEkLLFY4LDifoHdiCN/LlGBAdVJYsANaLqNYa1l/v0=",
version = "v2.10.0",
)
go_repository(
name = "com_github_raulk_go_watchdog",
importpath = "github.com/raulk/go-watchdog",
@@ -4304,6 +4310,12 @@ def prysm_deps():
sum = "h1:stTHdEoWg1pQ8riaP5ROrjS6zy6wewH/Q2iwnLCQUXY=",
version = "v1.0.0-20160220154919-db14e161995a",
)
go_repository(
name = "in_gopkg_cenkalti_backoff_v1",
importpath = "gopkg.in/cenkalti/backoff.v1",
sum = "h1:Arh75ttbsvlpVA7WtVpH4u9h6Zl46xuptxqLxPiSo4Y=",
version = "v1.1.0",
)
go_repository(
name = "in_gopkg_check_v1",
importpath = "gopkg.in/check.v1",

4
go.mod
View File

@@ -62,10 +62,11 @@ require (
github.com/prometheus/client_golang v1.20.0
github.com/prometheus/client_model v0.6.1
github.com/prometheus/prom2json v1.3.0
github.com/prysmaticlabs/fastssz v0.0.0-20240620202422-a981b8ef89d3
github.com/prysmaticlabs/fastssz v0.0.0-20241008181541-518c4ce73516
github.com/prysmaticlabs/go-bitfield v0.0.0-20240328144219-a1caa50c3a1e
github.com/prysmaticlabs/prombbolt v0.0.0-20210126082820-9b7adba6db7c
github.com/prysmaticlabs/protoc-gen-go-cast v0.0.0-20230228205207-28762a7b9294
github.com/r3labs/sse/v2 v2.10.0
github.com/rs/cors v1.7.0
github.com/schollz/progressbar/v3 v3.3.4
github.com/sirupsen/logrus v1.9.0
@@ -259,6 +260,7 @@ require (
golang.org/x/term v0.23.0 // indirect
golang.org/x/text v0.17.0 // indirect
golang.org/x/time v0.5.0 // indirect
gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect

9
go.sum
View File

@@ -897,8 +897,8 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/prometheus/prom2json v1.3.0 h1:BlqrtbT9lLH3ZsOVhXPsHzFrApCTKRifB7gjJuypu6Y=
github.com/prometheus/prom2json v1.3.0/go.mod h1:rMN7m0ApCowcoDlypBHlkNbp5eJQf/+1isKykIP5ZnM=
github.com/prysmaticlabs/fastssz v0.0.0-20240620202422-a981b8ef89d3 h1:0LZAwwHnsZFfXm4IK4rzFV4N5IVSKZKLmuBMA4kAlFk=
github.com/prysmaticlabs/fastssz v0.0.0-20240620202422-a981b8ef89d3/go.mod h1:h2OlIZD/M6wFvV3YMZbW16lFgh3Rsye00G44J2cwLyU=
github.com/prysmaticlabs/fastssz v0.0.0-20241008181541-518c4ce73516 h1:xuVAdtz5ShYblG2sPyb4gw01DF8InbOI/kBCQjk7NiM=
github.com/prysmaticlabs/fastssz v0.0.0-20241008181541-518c4ce73516/go.mod h1:h2OlIZD/M6wFvV3YMZbW16lFgh3Rsye00G44J2cwLyU=
github.com/prysmaticlabs/go-bitfield v0.0.0-20210108222456-8e92c3709aa0/go.mod h1:hCwmef+4qXWjv0jLDbQdWnL0Ol7cS7/lCSS26WR+u6s=
github.com/prysmaticlabs/go-bitfield v0.0.0-20240328144219-a1caa50c3a1e h1:ATgOe+abbzfx9kCPeXIW4fiWyDdxlwHw07j8UGhdTd4=
github.com/prysmaticlabs/go-bitfield v0.0.0-20240328144219-a1caa50c3a1e/go.mod h1:wmuf/mdK4VMD+jA9ThwcUKjg3a2XWM9cVfFYjDyY4j4=
@@ -914,6 +914,8 @@ github.com/quic-go/quic-go v0.46.0 h1:uuwLClEEyk1DNvchH8uCByQVjo3yKL9opKulExNDs7
github.com/quic-go/quic-go v0.46.0/go.mod h1:1dLehS7TIR64+vxGR70GDcatWTOtMX2PUtnKsjbTurI=
github.com/quic-go/webtransport-go v0.8.0 h1:HxSrwun11U+LlmwpgM1kEqIqH90IT4N8auv/cD7QFJg=
github.com/quic-go/webtransport-go v0.8.0/go.mod h1:N99tjprW432Ut5ONql/aUhSLT0YVSlwHohQsuac9WaM=
github.com/r3labs/sse/v2 v2.10.0 h1:hFEkLLFY4LDifoHdiCN/LlGBAdVJYsANaLqNYa1l/v0=
github.com/r3labs/sse/v2 v2.10.0/go.mod h1:Igau6Whc+F17QUgML1fYe1VPZzTV6EMCnYktEmkNJ7I=
github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk=
github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
@@ -1223,6 +1225,7 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191116160921-f9c825593386/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -1607,6 +1610,8 @@ google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6h
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/bsm/ratelimit.v1 v1.0.0-20160220154919-db14e161995a/go.mod h1:KF9sEfUPAXdG8Oev9e99iLGnl2uJMjc5B+4y3O7x610=
gopkg.in/cenkalti/backoff.v1 v1.1.0 h1:Arh75ttbsvlpVA7WtVpH4u9h6Zl46xuptxqLxPiSo4Y=
gopkg.in/cenkalti/backoff.v1 v1.1.0/go.mod h1:J6Vskwqd+OMVJl8C33mmtxTBs2gyzfv7UDAkHu8BrjI=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@@ -1,5 +1,5 @@
// Code generated by fastssz. DO NOT EDIT.
// Hash: 13c946aa898cca1afa84687b619bc5a10fc79a46340e98dcfb07dde835d39a0c
// Hash: 2874e1dadeb47411763f48fe31e5daaa91ac663e796933d9a508c2e7be94fa5e
package v1
import (
@@ -2395,7 +2395,10 @@ func (v *Validator) UnmarshalSSZ(buf []byte) error {
v.EffectiveBalance = ssz.UnmarshallUint64(buf[80:88])
// Field (3) 'Slashed'
v.Slashed = ssz.UnmarshalBool(buf[88:89])
v.Slashed, err = ssz.DecodeBool(buf[88:89])
if err != nil {
return err
}
// Field (4) 'ActivationEligibilityEpoch'
v.ActivationEligibilityEpoch = github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.Epoch(ssz.UnmarshallUint64(buf[89:97]))

View File

@@ -1,5 +1,5 @@
// Code generated by fastssz. DO NOT EDIT.
// Hash: bc8a0f7f6c8dadac6bcb0eaab2dea4888cc44c5b3f4fe9998a71e15f1a059399
// Hash: 298a6e797d2a244a4eee0e60b198b11fd30b4b8596a8a5b911dd2e14fafebdad
package eth
import (

View File

@@ -81,6 +81,11 @@ ssz_altair_objs = [
"BeaconBlockBodyAltair",
"BeaconStateAltair",
"ContributionAndProof",
"LightClientBootstrapAltair",
"LightClientFinalityUpdateAltair",
"LightClientHeaderAltair",
"LightClientOptimisticUpdateAltair",
"LightClientUpdateAltair",
"SignedBeaconBlockAltair",
"SignedContributionAndProof",
"SyncAggregate",
@@ -110,6 +115,11 @@ ssz_capella_objs = [
"BlindedBeaconBlockCapella",
"BuilderBidCapella",
"HistoricalSummary",
"LightClientBootstrapCapella",
"LightClientFinalityUpdateCapella",
"LightClientHeaderCapella",
"LightClientOptimisticUpdateCapella",
"LightClientUpdateCapella",
"SignedBLSToExecutionChange",
"SignedBeaconBlockCapella",
"SignedBlindedBeaconBlockCapella",
@@ -127,6 +137,11 @@ ssz_deneb_objs = [
"BlobSidecar",
"BlobSidecars",
"BuilderBidDeneb",
"LightClientBootstrapDeneb",
"LightClientFinalityUpdateDeneb",
"LightClientHeaderDeneb",
"LightClientOptimisticUpdateDeneb",
"LightClientUpdateDeneb",
"SignedBeaconBlockContentsDeneb",
"SignedBeaconBlockDeneb",
"SignedBlindedBeaconBlockDeneb",
@@ -136,7 +151,8 @@ ssz_electra_objs = [
"AggregateAttestationAndProofElectra",
"AttestationElectra",
"AttesterSlashingElectra",
"BeaconBlockElectra",
"BeaconBlockBodyElectra",
"BeaconBlockContentsElectra",
"BeaconBlockElectra",
"BeaconStateElectra",
"BlindedBeaconBlockBodyElectra",
@@ -333,6 +349,7 @@ ssz_proto_files(
"beacon_block.proto",
"beacon_state.proto",
"blobs.proto",
"light_client.proto",
"sync_committee.proto",
"withdrawals.proto",
],

View File

@@ -1,5 +1,5 @@
// Code generated by fastssz. DO NOT EDIT.
// Hash: bb838fc0c2dfdadd4a8274dd1b438b1051f7b84d7c8e7470900621284dba8f43
// Hash: 18a07a11eb3d1daaafe0b6b1ac8934e9333ea6eceed7d5ef30166b9c2fb50d39
package eth
import (
@@ -1747,6 +1747,651 @@ func (s *SyncAggregatorSelectionData) HashTreeRootWith(hh *ssz.Hasher) (err erro
return
}
// MarshalSSZ ssz marshals the LightClientHeaderAltair object
func (l *LightClientHeaderAltair) MarshalSSZ() ([]byte, error) {
return ssz.MarshalSSZ(l)
}
// MarshalSSZTo ssz marshals the LightClientHeaderAltair object to a target array
func (l *LightClientHeaderAltair) MarshalSSZTo(buf []byte) (dst []byte, err error) {
dst = buf
// Field (0) 'Beacon'
if l.Beacon == nil {
l.Beacon = new(BeaconBlockHeader)
}
if dst, err = l.Beacon.MarshalSSZTo(dst); err != nil {
return
}
return
}
// UnmarshalSSZ ssz unmarshals the LightClientHeaderAltair object
func (l *LightClientHeaderAltair) UnmarshalSSZ(buf []byte) error {
var err error
size := uint64(len(buf))
if size != 112 {
return ssz.ErrSize
}
// Field (0) 'Beacon'
if l.Beacon == nil {
l.Beacon = new(BeaconBlockHeader)
}
if err = l.Beacon.UnmarshalSSZ(buf[0:112]); err != nil {
return err
}
return err
}
// SizeSSZ returns the ssz encoded size in bytes for the LightClientHeaderAltair object
func (l *LightClientHeaderAltair) SizeSSZ() (size int) {
size = 112
return
}
// HashTreeRoot ssz hashes the LightClientHeaderAltair object
func (l *LightClientHeaderAltair) HashTreeRoot() ([32]byte, error) {
return ssz.HashWithDefaultHasher(l)
}
// HashTreeRootWith ssz hashes the LightClientHeaderAltair object with a hasher
func (l *LightClientHeaderAltair) HashTreeRootWith(hh *ssz.Hasher) (err error) {
indx := hh.Index()
// Field (0) 'Beacon'
if err = l.Beacon.HashTreeRootWith(hh); err != nil {
return
}
hh.Merkleize(indx)
return
}
// MarshalSSZ ssz marshals the LightClientBootstrapAltair object
func (l *LightClientBootstrapAltair) MarshalSSZ() ([]byte, error) {
return ssz.MarshalSSZ(l)
}
// MarshalSSZTo ssz marshals the LightClientBootstrapAltair object to a target array
func (l *LightClientBootstrapAltair) MarshalSSZTo(buf []byte) (dst []byte, err error) {
dst = buf
// Field (0) 'Header'
if l.Header == nil {
l.Header = new(LightClientHeaderAltair)
}
if dst, err = l.Header.MarshalSSZTo(dst); err != nil {
return
}
// Field (1) 'CurrentSyncCommittee'
if l.CurrentSyncCommittee == nil {
l.CurrentSyncCommittee = new(SyncCommittee)
}
if dst, err = l.CurrentSyncCommittee.MarshalSSZTo(dst); err != nil {
return
}
// Field (2) 'CurrentSyncCommitteeBranch'
if size := len(l.CurrentSyncCommitteeBranch); size != 5 {
err = ssz.ErrVectorLengthFn("--.CurrentSyncCommitteeBranch", size, 5)
return
}
for ii := 0; ii < 5; ii++ {
if size := len(l.CurrentSyncCommitteeBranch[ii]); size != 32 {
err = ssz.ErrBytesLengthFn("--.CurrentSyncCommitteeBranch[ii]", size, 32)
return
}
dst = append(dst, l.CurrentSyncCommitteeBranch[ii]...)
}
return
}
// UnmarshalSSZ ssz unmarshals the LightClientBootstrapAltair object
func (l *LightClientBootstrapAltair) UnmarshalSSZ(buf []byte) error {
var err error
size := uint64(len(buf))
if size != 24896 {
return ssz.ErrSize
}
// Field (0) 'Header'
if l.Header == nil {
l.Header = new(LightClientHeaderAltair)
}
if err = l.Header.UnmarshalSSZ(buf[0:112]); err != nil {
return err
}
// Field (1) 'CurrentSyncCommittee'
if l.CurrentSyncCommittee == nil {
l.CurrentSyncCommittee = new(SyncCommittee)
}
if err = l.CurrentSyncCommittee.UnmarshalSSZ(buf[112:24736]); err != nil {
return err
}
// Field (2) 'CurrentSyncCommitteeBranch'
l.CurrentSyncCommitteeBranch = make([][]byte, 5)
for ii := 0; ii < 5; ii++ {
if cap(l.CurrentSyncCommitteeBranch[ii]) == 0 {
l.CurrentSyncCommitteeBranch[ii] = make([]byte, 0, len(buf[24736:24896][ii*32:(ii+1)*32]))
}
l.CurrentSyncCommitteeBranch[ii] = append(l.CurrentSyncCommitteeBranch[ii], buf[24736:24896][ii*32:(ii+1)*32]...)
}
return err
}
// SizeSSZ returns the ssz encoded size in bytes for the LightClientBootstrapAltair object
func (l *LightClientBootstrapAltair) SizeSSZ() (size int) {
size = 24896
return
}
// HashTreeRoot ssz hashes the LightClientBootstrapAltair object
func (l *LightClientBootstrapAltair) HashTreeRoot() ([32]byte, error) {
return ssz.HashWithDefaultHasher(l)
}
// HashTreeRootWith ssz hashes the LightClientBootstrapAltair object with a hasher
func (l *LightClientBootstrapAltair) HashTreeRootWith(hh *ssz.Hasher) (err error) {
indx := hh.Index()
// Field (0) 'Header'
if err = l.Header.HashTreeRootWith(hh); err != nil {
return
}
// Field (1) 'CurrentSyncCommittee'
if err = l.CurrentSyncCommittee.HashTreeRootWith(hh); err != nil {
return
}
// Field (2) 'CurrentSyncCommitteeBranch'
{
if size := len(l.CurrentSyncCommitteeBranch); size != 5 {
err = ssz.ErrVectorLengthFn("--.CurrentSyncCommitteeBranch", size, 5)
return
}
subIndx := hh.Index()
for _, i := range l.CurrentSyncCommitteeBranch {
if len(i) != 32 {
err = ssz.ErrBytesLength
return
}
hh.Append(i)
}
hh.Merkleize(subIndx)
}
hh.Merkleize(indx)
return
}
// MarshalSSZ ssz marshals the LightClientUpdateAltair object
func (l *LightClientUpdateAltair) MarshalSSZ() ([]byte, error) {
return ssz.MarshalSSZ(l)
}
// MarshalSSZTo ssz marshals the LightClientUpdateAltair object to a target array
func (l *LightClientUpdateAltair) MarshalSSZTo(buf []byte) (dst []byte, err error) {
dst = buf
// Field (0) 'AttestedHeader'
if l.AttestedHeader == nil {
l.AttestedHeader = new(LightClientHeaderAltair)
}
if dst, err = l.AttestedHeader.MarshalSSZTo(dst); err != nil {
return
}
// Field (1) 'NextSyncCommittee'
if l.NextSyncCommittee == nil {
l.NextSyncCommittee = new(SyncCommittee)
}
if dst, err = l.NextSyncCommittee.MarshalSSZTo(dst); err != nil {
return
}
// Field (2) 'NextSyncCommitteeBranch'
if size := len(l.NextSyncCommitteeBranch); size != 5 {
err = ssz.ErrVectorLengthFn("--.NextSyncCommitteeBranch", size, 5)
return
}
for ii := 0; ii < 5; ii++ {
if size := len(l.NextSyncCommitteeBranch[ii]); size != 32 {
err = ssz.ErrBytesLengthFn("--.NextSyncCommitteeBranch[ii]", size, 32)
return
}
dst = append(dst, l.NextSyncCommitteeBranch[ii]...)
}
// Field (3) 'FinalizedHeader'
if l.FinalizedHeader == nil {
l.FinalizedHeader = new(LightClientHeaderAltair)
}
if dst, err = l.FinalizedHeader.MarshalSSZTo(dst); err != nil {
return
}
// Field (4) 'FinalityBranch'
if size := len(l.FinalityBranch); size != 6 {
err = ssz.ErrVectorLengthFn("--.FinalityBranch", size, 6)
return
}
for ii := 0; ii < 6; ii++ {
if size := len(l.FinalityBranch[ii]); size != 32 {
err = ssz.ErrBytesLengthFn("--.FinalityBranch[ii]", size, 32)
return
}
dst = append(dst, l.FinalityBranch[ii]...)
}
// Field (5) 'SyncAggregate'
if l.SyncAggregate == nil {
l.SyncAggregate = new(SyncAggregate)
}
if dst, err = l.SyncAggregate.MarshalSSZTo(dst); err != nil {
return
}
// Field (6) 'SignatureSlot'
dst = ssz.MarshalUint64(dst, uint64(l.SignatureSlot))
return
}
// UnmarshalSSZ ssz unmarshals the LightClientUpdateAltair object
func (l *LightClientUpdateAltair) UnmarshalSSZ(buf []byte) error {
var err error
size := uint64(len(buf))
if size != 25368 {
return ssz.ErrSize
}
// Field (0) 'AttestedHeader'
if l.AttestedHeader == nil {
l.AttestedHeader = new(LightClientHeaderAltair)
}
if err = l.AttestedHeader.UnmarshalSSZ(buf[0:112]); err != nil {
return err
}
// Field (1) 'NextSyncCommittee'
if l.NextSyncCommittee == nil {
l.NextSyncCommittee = new(SyncCommittee)
}
if err = l.NextSyncCommittee.UnmarshalSSZ(buf[112:24736]); err != nil {
return err
}
// Field (2) 'NextSyncCommitteeBranch'
l.NextSyncCommitteeBranch = make([][]byte, 5)
for ii := 0; ii < 5; ii++ {
if cap(l.NextSyncCommitteeBranch[ii]) == 0 {
l.NextSyncCommitteeBranch[ii] = make([]byte, 0, len(buf[24736:24896][ii*32:(ii+1)*32]))
}
l.NextSyncCommitteeBranch[ii] = append(l.NextSyncCommitteeBranch[ii], buf[24736:24896][ii*32:(ii+1)*32]...)
}
// Field (3) 'FinalizedHeader'
if l.FinalizedHeader == nil {
l.FinalizedHeader = new(LightClientHeaderAltair)
}
if err = l.FinalizedHeader.UnmarshalSSZ(buf[24896:25008]); err != nil {
return err
}
// Field (4) 'FinalityBranch'
l.FinalityBranch = make([][]byte, 6)
for ii := 0; ii < 6; ii++ {
if cap(l.FinalityBranch[ii]) == 0 {
l.FinalityBranch[ii] = make([]byte, 0, len(buf[25008:25200][ii*32:(ii+1)*32]))
}
l.FinalityBranch[ii] = append(l.FinalityBranch[ii], buf[25008:25200][ii*32:(ii+1)*32]...)
}
// Field (5) 'SyncAggregate'
if l.SyncAggregate == nil {
l.SyncAggregate = new(SyncAggregate)
}
if err = l.SyncAggregate.UnmarshalSSZ(buf[25200:25360]); err != nil {
return err
}
// Field (6) 'SignatureSlot'
l.SignatureSlot = github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.Slot(ssz.UnmarshallUint64(buf[25360:25368]))
return err
}
// SizeSSZ returns the ssz encoded size in bytes for the LightClientUpdateAltair object
func (l *LightClientUpdateAltair) SizeSSZ() (size int) {
size = 25368
return
}
// HashTreeRoot ssz hashes the LightClientUpdateAltair object
func (l *LightClientUpdateAltair) HashTreeRoot() ([32]byte, error) {
return ssz.HashWithDefaultHasher(l)
}
// HashTreeRootWith ssz hashes the LightClientUpdateAltair object with a hasher
func (l *LightClientUpdateAltair) HashTreeRootWith(hh *ssz.Hasher) (err error) {
indx := hh.Index()
// Field (0) 'AttestedHeader'
if err = l.AttestedHeader.HashTreeRootWith(hh); err != nil {
return
}
// Field (1) 'NextSyncCommittee'
if err = l.NextSyncCommittee.HashTreeRootWith(hh); err != nil {
return
}
// Field (2) 'NextSyncCommitteeBranch'
{
if size := len(l.NextSyncCommitteeBranch); size != 5 {
err = ssz.ErrVectorLengthFn("--.NextSyncCommitteeBranch", size, 5)
return
}
subIndx := hh.Index()
for _, i := range l.NextSyncCommitteeBranch {
if len(i) != 32 {
err = ssz.ErrBytesLength
return
}
hh.Append(i)
}
hh.Merkleize(subIndx)
}
// Field (3) 'FinalizedHeader'
if err = l.FinalizedHeader.HashTreeRootWith(hh); err != nil {
return
}
// Field (4) 'FinalityBranch'
{
if size := len(l.FinalityBranch); size != 6 {
err = ssz.ErrVectorLengthFn("--.FinalityBranch", size, 6)
return
}
subIndx := hh.Index()
for _, i := range l.FinalityBranch {
if len(i) != 32 {
err = ssz.ErrBytesLength
return
}
hh.Append(i)
}
hh.Merkleize(subIndx)
}
// Field (5) 'SyncAggregate'
if err = l.SyncAggregate.HashTreeRootWith(hh); err != nil {
return
}
// Field (6) 'SignatureSlot'
hh.PutUint64(uint64(l.SignatureSlot))
hh.Merkleize(indx)
return
}
// MarshalSSZ ssz marshals the LightClientFinalityUpdateAltair object
func (l *LightClientFinalityUpdateAltair) MarshalSSZ() ([]byte, error) {
return ssz.MarshalSSZ(l)
}
// MarshalSSZTo ssz marshals the LightClientFinalityUpdateAltair object to a target array
func (l *LightClientFinalityUpdateAltair) MarshalSSZTo(buf []byte) (dst []byte, err error) {
dst = buf
// Field (0) 'AttestedHeader'
if l.AttestedHeader == nil {
l.AttestedHeader = new(LightClientHeaderAltair)
}
if dst, err = l.AttestedHeader.MarshalSSZTo(dst); err != nil {
return
}
// Field (1) 'FinalizedHeader'
if l.FinalizedHeader == nil {
l.FinalizedHeader = new(LightClientHeaderAltair)
}
if dst, err = l.FinalizedHeader.MarshalSSZTo(dst); err != nil {
return
}
// Field (2) 'FinalityBranch'
if size := len(l.FinalityBranch); size != 6 {
err = ssz.ErrVectorLengthFn("--.FinalityBranch", size, 6)
return
}
for ii := 0; ii < 6; ii++ {
if size := len(l.FinalityBranch[ii]); size != 32 {
err = ssz.ErrBytesLengthFn("--.FinalityBranch[ii]", size, 32)
return
}
dst = append(dst, l.FinalityBranch[ii]...)
}
// Field (3) 'SyncAggregate'
if l.SyncAggregate == nil {
l.SyncAggregate = new(SyncAggregate)
}
if dst, err = l.SyncAggregate.MarshalSSZTo(dst); err != nil {
return
}
// Field (4) 'SignatureSlot'
dst = ssz.MarshalUint64(dst, uint64(l.SignatureSlot))
return
}
// UnmarshalSSZ ssz unmarshals the LightClientFinalityUpdateAltair object
func (l *LightClientFinalityUpdateAltair) UnmarshalSSZ(buf []byte) error {
var err error
size := uint64(len(buf))
if size != 584 {
return ssz.ErrSize
}
// Field (0) 'AttestedHeader'
if l.AttestedHeader == nil {
l.AttestedHeader = new(LightClientHeaderAltair)
}
if err = l.AttestedHeader.UnmarshalSSZ(buf[0:112]); err != nil {
return err
}
// Field (1) 'FinalizedHeader'
if l.FinalizedHeader == nil {
l.FinalizedHeader = new(LightClientHeaderAltair)
}
if err = l.FinalizedHeader.UnmarshalSSZ(buf[112:224]); err != nil {
return err
}
// Field (2) 'FinalityBranch'
l.FinalityBranch = make([][]byte, 6)
for ii := 0; ii < 6; ii++ {
if cap(l.FinalityBranch[ii]) == 0 {
l.FinalityBranch[ii] = make([]byte, 0, len(buf[224:416][ii*32:(ii+1)*32]))
}
l.FinalityBranch[ii] = append(l.FinalityBranch[ii], buf[224:416][ii*32:(ii+1)*32]...)
}
// Field (3) 'SyncAggregate'
if l.SyncAggregate == nil {
l.SyncAggregate = new(SyncAggregate)
}
if err = l.SyncAggregate.UnmarshalSSZ(buf[416:576]); err != nil {
return err
}
// Field (4) 'SignatureSlot'
l.SignatureSlot = github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.Slot(ssz.UnmarshallUint64(buf[576:584]))
return err
}
// SizeSSZ returns the ssz encoded size in bytes for the LightClientFinalityUpdateAltair object
func (l *LightClientFinalityUpdateAltair) SizeSSZ() (size int) {
size = 584
return
}
// HashTreeRoot ssz hashes the LightClientFinalityUpdateAltair object
func (l *LightClientFinalityUpdateAltair) HashTreeRoot() ([32]byte, error) {
return ssz.HashWithDefaultHasher(l)
}
// HashTreeRootWith ssz hashes the LightClientFinalityUpdateAltair object with a hasher
func (l *LightClientFinalityUpdateAltair) HashTreeRootWith(hh *ssz.Hasher) (err error) {
indx := hh.Index()
// Field (0) 'AttestedHeader'
if err = l.AttestedHeader.HashTreeRootWith(hh); err != nil {
return
}
// Field (1) 'FinalizedHeader'
if err = l.FinalizedHeader.HashTreeRootWith(hh); err != nil {
return
}
// Field (2) 'FinalityBranch'
{
if size := len(l.FinalityBranch); size != 6 {
err = ssz.ErrVectorLengthFn("--.FinalityBranch", size, 6)
return
}
subIndx := hh.Index()
for _, i := range l.FinalityBranch {
if len(i) != 32 {
err = ssz.ErrBytesLength
return
}
hh.Append(i)
}
hh.Merkleize(subIndx)
}
// Field (3) 'SyncAggregate'
if err = l.SyncAggregate.HashTreeRootWith(hh); err != nil {
return
}
// Field (4) 'SignatureSlot'
hh.PutUint64(uint64(l.SignatureSlot))
hh.Merkleize(indx)
return
}
// MarshalSSZ ssz marshals the LightClientOptimisticUpdateAltair object
func (l *LightClientOptimisticUpdateAltair) MarshalSSZ() ([]byte, error) {
return ssz.MarshalSSZ(l)
}
// MarshalSSZTo ssz marshals the LightClientOptimisticUpdateAltair object to a target array
func (l *LightClientOptimisticUpdateAltair) MarshalSSZTo(buf []byte) (dst []byte, err error) {
dst = buf
// Field (0) 'AttestedHeader'
if l.AttestedHeader == nil {
l.AttestedHeader = new(LightClientHeaderAltair)
}
if dst, err = l.AttestedHeader.MarshalSSZTo(dst); err != nil {
return
}
// Field (1) 'SyncAggregate'
if l.SyncAggregate == nil {
l.SyncAggregate = new(SyncAggregate)
}
if dst, err = l.SyncAggregate.MarshalSSZTo(dst); err != nil {
return
}
// Field (2) 'SignatureSlot'
dst = ssz.MarshalUint64(dst, uint64(l.SignatureSlot))
return
}
// UnmarshalSSZ ssz unmarshals the LightClientOptimisticUpdateAltair object
func (l *LightClientOptimisticUpdateAltair) UnmarshalSSZ(buf []byte) error {
var err error
size := uint64(len(buf))
if size != 280 {
return ssz.ErrSize
}
// Field (0) 'AttestedHeader'
if l.AttestedHeader == nil {
l.AttestedHeader = new(LightClientHeaderAltair)
}
if err = l.AttestedHeader.UnmarshalSSZ(buf[0:112]); err != nil {
return err
}
// Field (1) 'SyncAggregate'
if l.SyncAggregate == nil {
l.SyncAggregate = new(SyncAggregate)
}
if err = l.SyncAggregate.UnmarshalSSZ(buf[112:272]); err != nil {
return err
}
// Field (2) 'SignatureSlot'
l.SignatureSlot = github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.Slot(ssz.UnmarshallUint64(buf[272:280]))
return err
}
// SizeSSZ returns the ssz encoded size in bytes for the LightClientOptimisticUpdateAltair object
func (l *LightClientOptimisticUpdateAltair) SizeSSZ() (size int) {
size = 280
return
}
// HashTreeRoot ssz hashes the LightClientOptimisticUpdateAltair object
func (l *LightClientOptimisticUpdateAltair) HashTreeRoot() ([32]byte, error) {
return ssz.HashWithDefaultHasher(l)
}
// HashTreeRootWith ssz hashes the LightClientOptimisticUpdateAltair object with a hasher
func (l *LightClientOptimisticUpdateAltair) HashTreeRootWith(hh *ssz.Hasher) (err error) {
indx := hh.Index()
// Field (0) 'AttestedHeader'
if err = l.AttestedHeader.HashTreeRootWith(hh); err != nil {
return
}
// Field (1) 'SyncAggregate'
if err = l.SyncAggregate.HashTreeRootWith(hh); err != nil {
return
}
// Field (2) 'SignatureSlot'
hh.PutUint64(uint64(l.SignatureSlot))
hh.Merkleize(indx)
return
}
// MarshalSSZ ssz marshals the SyncCommitteeMessage object
func (s *SyncCommitteeMessage) MarshalSSZ() ([]byte, error) {
return ssz.MarshalSSZ(s)

View File

@@ -1,5 +1,5 @@
// Code generated by fastssz. DO NOT EDIT.
// Hash: 693cad07de8560b2681132d912aebb927e668fe15e5cb9f42e8a36bbac6e2c5e
// Hash: c6614861443f105e2d5445ca29187cc78c2a929161d0a15b36ce2f0e6517a0ea
package eth
import (

View File

@@ -1,5 +1,5 @@
// Code generated by fastssz. DO NOT EDIT.
// Hash: a5507ef7d71897486989f37eb4dbb19fc2c49e7c47f244291a9f3122c9bfe546
// Hash: 6bee0cf7c5707af68be518a221b248ce37edd4b0b1e6fec9703c6152a5107a1d
package eth
import (
@@ -2729,6 +2729,877 @@ func (h *HistoricalSummary) HashTreeRootWith(hh *ssz.Hasher) (err error) {
return
}
// MarshalSSZ ssz marshals the LightClientHeaderCapella object
func (l *LightClientHeaderCapella) MarshalSSZ() ([]byte, error) {
return ssz.MarshalSSZ(l)
}
// MarshalSSZTo ssz marshals the LightClientHeaderCapella object to a target array
func (l *LightClientHeaderCapella) MarshalSSZTo(buf []byte) (dst []byte, err error) {
dst = buf
offset := int(244)
// Field (0) 'Beacon'
if l.Beacon == nil {
l.Beacon = new(BeaconBlockHeader)
}
if dst, err = l.Beacon.MarshalSSZTo(dst); err != nil {
return
}
// Offset (1) 'Execution'
dst = ssz.WriteOffset(dst, offset)
if l.Execution == nil {
l.Execution = new(v1.ExecutionPayloadHeaderCapella)
}
offset += l.Execution.SizeSSZ()
// Field (2) 'ExecutionBranch'
if size := len(l.ExecutionBranch); size != 4 {
err = ssz.ErrVectorLengthFn("--.ExecutionBranch", size, 4)
return
}
for ii := 0; ii < 4; ii++ {
if size := len(l.ExecutionBranch[ii]); size != 32 {
err = ssz.ErrBytesLengthFn("--.ExecutionBranch[ii]", size, 32)
return
}
dst = append(dst, l.ExecutionBranch[ii]...)
}
// Field (1) 'Execution'
if dst, err = l.Execution.MarshalSSZTo(dst); err != nil {
return
}
return
}
// UnmarshalSSZ ssz unmarshals the LightClientHeaderCapella object
func (l *LightClientHeaderCapella) UnmarshalSSZ(buf []byte) error {
var err error
size := uint64(len(buf))
if size < 244 {
return ssz.ErrSize
}
tail := buf
var o1 uint64
// Field (0) 'Beacon'
if l.Beacon == nil {
l.Beacon = new(BeaconBlockHeader)
}
if err = l.Beacon.UnmarshalSSZ(buf[0:112]); err != nil {
return err
}
// Offset (1) 'Execution'
if o1 = ssz.ReadOffset(buf[112:116]); o1 > size {
return ssz.ErrOffset
}
if o1 != 244 {
return ssz.ErrInvalidVariableOffset
}
// Field (2) 'ExecutionBranch'
l.ExecutionBranch = make([][]byte, 4)
for ii := 0; ii < 4; ii++ {
if cap(l.ExecutionBranch[ii]) == 0 {
l.ExecutionBranch[ii] = make([]byte, 0, len(buf[116:244][ii*32:(ii+1)*32]))
}
l.ExecutionBranch[ii] = append(l.ExecutionBranch[ii], buf[116:244][ii*32:(ii+1)*32]...)
}
// Field (1) 'Execution'
{
buf = tail[o1:]
if l.Execution == nil {
l.Execution = new(v1.ExecutionPayloadHeaderCapella)
}
if err = l.Execution.UnmarshalSSZ(buf); err != nil {
return err
}
}
return err
}
// SizeSSZ returns the ssz encoded size in bytes for the LightClientHeaderCapella object
func (l *LightClientHeaderCapella) SizeSSZ() (size int) {
size = 244
// Field (1) 'Execution'
if l.Execution == nil {
l.Execution = new(v1.ExecutionPayloadHeaderCapella)
}
size += l.Execution.SizeSSZ()
return
}
// HashTreeRoot ssz hashes the LightClientHeaderCapella object
func (l *LightClientHeaderCapella) HashTreeRoot() ([32]byte, error) {
return ssz.HashWithDefaultHasher(l)
}
// HashTreeRootWith ssz hashes the LightClientHeaderCapella object with a hasher
func (l *LightClientHeaderCapella) HashTreeRootWith(hh *ssz.Hasher) (err error) {
indx := hh.Index()
// Field (0) 'Beacon'
if err = l.Beacon.HashTreeRootWith(hh); err != nil {
return
}
// Field (1) 'Execution'
if err = l.Execution.HashTreeRootWith(hh); err != nil {
return
}
// Field (2) 'ExecutionBranch'
{
if size := len(l.ExecutionBranch); size != 4 {
err = ssz.ErrVectorLengthFn("--.ExecutionBranch", size, 4)
return
}
subIndx := hh.Index()
for _, i := range l.ExecutionBranch {
if len(i) != 32 {
err = ssz.ErrBytesLength
return
}
hh.Append(i)
}
hh.Merkleize(subIndx)
}
hh.Merkleize(indx)
return
}
// MarshalSSZ ssz marshals the LightClientBootstrapCapella object
func (l *LightClientBootstrapCapella) MarshalSSZ() ([]byte, error) {
return ssz.MarshalSSZ(l)
}
// MarshalSSZTo ssz marshals the LightClientBootstrapCapella object to a target array
func (l *LightClientBootstrapCapella) MarshalSSZTo(buf []byte) (dst []byte, err error) {
dst = buf
offset := int(24788)
// Offset (0) 'Header'
dst = ssz.WriteOffset(dst, offset)
if l.Header == nil {
l.Header = new(LightClientHeaderCapella)
}
offset += l.Header.SizeSSZ()
// Field (1) 'CurrentSyncCommittee'
if l.CurrentSyncCommittee == nil {
l.CurrentSyncCommittee = new(SyncCommittee)
}
if dst, err = l.CurrentSyncCommittee.MarshalSSZTo(dst); err != nil {
return
}
// Field (2) 'CurrentSyncCommitteeBranch'
if size := len(l.CurrentSyncCommitteeBranch); size != 5 {
err = ssz.ErrVectorLengthFn("--.CurrentSyncCommitteeBranch", size, 5)
return
}
for ii := 0; ii < 5; ii++ {
if size := len(l.CurrentSyncCommitteeBranch[ii]); size != 32 {
err = ssz.ErrBytesLengthFn("--.CurrentSyncCommitteeBranch[ii]", size, 32)
return
}
dst = append(dst, l.CurrentSyncCommitteeBranch[ii]...)
}
// Field (0) 'Header'
if dst, err = l.Header.MarshalSSZTo(dst); err != nil {
return
}
return
}
// UnmarshalSSZ ssz unmarshals the LightClientBootstrapCapella object
func (l *LightClientBootstrapCapella) UnmarshalSSZ(buf []byte) error {
var err error
size := uint64(len(buf))
if size < 24788 {
return ssz.ErrSize
}
tail := buf
var o0 uint64
// Offset (0) 'Header'
if o0 = ssz.ReadOffset(buf[0:4]); o0 > size {
return ssz.ErrOffset
}
if o0 != 24788 {
return ssz.ErrInvalidVariableOffset
}
// Field (1) 'CurrentSyncCommittee'
if l.CurrentSyncCommittee == nil {
l.CurrentSyncCommittee = new(SyncCommittee)
}
if err = l.CurrentSyncCommittee.UnmarshalSSZ(buf[4:24628]); err != nil {
return err
}
// Field (2) 'CurrentSyncCommitteeBranch'
l.CurrentSyncCommitteeBranch = make([][]byte, 5)
for ii := 0; ii < 5; ii++ {
if cap(l.CurrentSyncCommitteeBranch[ii]) == 0 {
l.CurrentSyncCommitteeBranch[ii] = make([]byte, 0, len(buf[24628:24788][ii*32:(ii+1)*32]))
}
l.CurrentSyncCommitteeBranch[ii] = append(l.CurrentSyncCommitteeBranch[ii], buf[24628:24788][ii*32:(ii+1)*32]...)
}
// Field (0) 'Header'
{
buf = tail[o0:]
if l.Header == nil {
l.Header = new(LightClientHeaderCapella)
}
if err = l.Header.UnmarshalSSZ(buf); err != nil {
return err
}
}
return err
}
// SizeSSZ returns the ssz encoded size in bytes for the LightClientBootstrapCapella object
func (l *LightClientBootstrapCapella) SizeSSZ() (size int) {
size = 24788
// Field (0) 'Header'
if l.Header == nil {
l.Header = new(LightClientHeaderCapella)
}
size += l.Header.SizeSSZ()
return
}
// HashTreeRoot ssz hashes the LightClientBootstrapCapella object
func (l *LightClientBootstrapCapella) HashTreeRoot() ([32]byte, error) {
return ssz.HashWithDefaultHasher(l)
}
// HashTreeRootWith ssz hashes the LightClientBootstrapCapella object with a hasher
func (l *LightClientBootstrapCapella) HashTreeRootWith(hh *ssz.Hasher) (err error) {
indx := hh.Index()
// Field (0) 'Header'
if err = l.Header.HashTreeRootWith(hh); err != nil {
return
}
// Field (1) 'CurrentSyncCommittee'
if err = l.CurrentSyncCommittee.HashTreeRootWith(hh); err != nil {
return
}
// Field (2) 'CurrentSyncCommitteeBranch'
{
if size := len(l.CurrentSyncCommitteeBranch); size != 5 {
err = ssz.ErrVectorLengthFn("--.CurrentSyncCommitteeBranch", size, 5)
return
}
subIndx := hh.Index()
for _, i := range l.CurrentSyncCommitteeBranch {
if len(i) != 32 {
err = ssz.ErrBytesLength
return
}
hh.Append(i)
}
hh.Merkleize(subIndx)
}
hh.Merkleize(indx)
return
}
// MarshalSSZ ssz marshals the LightClientUpdateCapella object
func (l *LightClientUpdateCapella) MarshalSSZ() ([]byte, error) {
return ssz.MarshalSSZ(l)
}
// MarshalSSZTo ssz marshals the LightClientUpdateCapella object to a target array
func (l *LightClientUpdateCapella) MarshalSSZTo(buf []byte) (dst []byte, err error) {
dst = buf
offset := int(25152)
// Offset (0) 'AttestedHeader'
dst = ssz.WriteOffset(dst, offset)
if l.AttestedHeader == nil {
l.AttestedHeader = new(LightClientHeaderCapella)
}
offset += l.AttestedHeader.SizeSSZ()
// Field (1) 'NextSyncCommittee'
if l.NextSyncCommittee == nil {
l.NextSyncCommittee = new(SyncCommittee)
}
if dst, err = l.NextSyncCommittee.MarshalSSZTo(dst); err != nil {
return
}
// Field (2) 'NextSyncCommitteeBranch'
if size := len(l.NextSyncCommitteeBranch); size != 5 {
err = ssz.ErrVectorLengthFn("--.NextSyncCommitteeBranch", size, 5)
return
}
for ii := 0; ii < 5; ii++ {
if size := len(l.NextSyncCommitteeBranch[ii]); size != 32 {
err = ssz.ErrBytesLengthFn("--.NextSyncCommitteeBranch[ii]", size, 32)
return
}
dst = append(dst, l.NextSyncCommitteeBranch[ii]...)
}
// Offset (3) 'FinalizedHeader'
dst = ssz.WriteOffset(dst, offset)
if l.FinalizedHeader == nil {
l.FinalizedHeader = new(LightClientHeaderCapella)
}
offset += l.FinalizedHeader.SizeSSZ()
// Field (4) 'FinalityBranch'
if size := len(l.FinalityBranch); size != 6 {
err = ssz.ErrVectorLengthFn("--.FinalityBranch", size, 6)
return
}
for ii := 0; ii < 6; ii++ {
if size := len(l.FinalityBranch[ii]); size != 32 {
err = ssz.ErrBytesLengthFn("--.FinalityBranch[ii]", size, 32)
return
}
dst = append(dst, l.FinalityBranch[ii]...)
}
// Field (5) 'SyncAggregate'
if l.SyncAggregate == nil {
l.SyncAggregate = new(SyncAggregate)
}
if dst, err = l.SyncAggregate.MarshalSSZTo(dst); err != nil {
return
}
// Field (6) 'SignatureSlot'
dst = ssz.MarshalUint64(dst, uint64(l.SignatureSlot))
// Field (0) 'AttestedHeader'
if dst, err = l.AttestedHeader.MarshalSSZTo(dst); err != nil {
return
}
// Field (3) 'FinalizedHeader'
if dst, err = l.FinalizedHeader.MarshalSSZTo(dst); err != nil {
return
}
return
}
// UnmarshalSSZ ssz unmarshals the LightClientUpdateCapella object
func (l *LightClientUpdateCapella) UnmarshalSSZ(buf []byte) error {
var err error
size := uint64(len(buf))
if size < 25152 {
return ssz.ErrSize
}
tail := buf
var o0, o3 uint64
// Offset (0) 'AttestedHeader'
if o0 = ssz.ReadOffset(buf[0:4]); o0 > size {
return ssz.ErrOffset
}
if o0 != 25152 {
return ssz.ErrInvalidVariableOffset
}
// Field (1) 'NextSyncCommittee'
if l.NextSyncCommittee == nil {
l.NextSyncCommittee = new(SyncCommittee)
}
if err = l.NextSyncCommittee.UnmarshalSSZ(buf[4:24628]); err != nil {
return err
}
// Field (2) 'NextSyncCommitteeBranch'
l.NextSyncCommitteeBranch = make([][]byte, 5)
for ii := 0; ii < 5; ii++ {
if cap(l.NextSyncCommitteeBranch[ii]) == 0 {
l.NextSyncCommitteeBranch[ii] = make([]byte, 0, len(buf[24628:24788][ii*32:(ii+1)*32]))
}
l.NextSyncCommitteeBranch[ii] = append(l.NextSyncCommitteeBranch[ii], buf[24628:24788][ii*32:(ii+1)*32]...)
}
// Offset (3) 'FinalizedHeader'
if o3 = ssz.ReadOffset(buf[24788:24792]); o3 > size || o0 > o3 {
return ssz.ErrOffset
}
// Field (4) 'FinalityBranch'
l.FinalityBranch = make([][]byte, 6)
for ii := 0; ii < 6; ii++ {
if cap(l.FinalityBranch[ii]) == 0 {
l.FinalityBranch[ii] = make([]byte, 0, len(buf[24792:24984][ii*32:(ii+1)*32]))
}
l.FinalityBranch[ii] = append(l.FinalityBranch[ii], buf[24792:24984][ii*32:(ii+1)*32]...)
}
// Field (5) 'SyncAggregate'
if l.SyncAggregate == nil {
l.SyncAggregate = new(SyncAggregate)
}
if err = l.SyncAggregate.UnmarshalSSZ(buf[24984:25144]); err != nil {
return err
}
// Field (6) 'SignatureSlot'
l.SignatureSlot = github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.Slot(ssz.UnmarshallUint64(buf[25144:25152]))
// Field (0) 'AttestedHeader'
{
buf = tail[o0:o3]
if l.AttestedHeader == nil {
l.AttestedHeader = new(LightClientHeaderCapella)
}
if err = l.AttestedHeader.UnmarshalSSZ(buf); err != nil {
return err
}
}
// Field (3) 'FinalizedHeader'
{
buf = tail[o3:]
if l.FinalizedHeader == nil {
l.FinalizedHeader = new(LightClientHeaderCapella)
}
if err = l.FinalizedHeader.UnmarshalSSZ(buf); err != nil {
return err
}
}
return err
}
// SizeSSZ returns the ssz encoded size in bytes for the LightClientUpdateCapella object
func (l *LightClientUpdateCapella) SizeSSZ() (size int) {
size = 25152
// Field (0) 'AttestedHeader'
if l.AttestedHeader == nil {
l.AttestedHeader = new(LightClientHeaderCapella)
}
size += l.AttestedHeader.SizeSSZ()
// Field (3) 'FinalizedHeader'
if l.FinalizedHeader == nil {
l.FinalizedHeader = new(LightClientHeaderCapella)
}
size += l.FinalizedHeader.SizeSSZ()
return
}
// HashTreeRoot ssz hashes the LightClientUpdateCapella object
func (l *LightClientUpdateCapella) HashTreeRoot() ([32]byte, error) {
return ssz.HashWithDefaultHasher(l)
}
// HashTreeRootWith ssz hashes the LightClientUpdateCapella object with a hasher
func (l *LightClientUpdateCapella) HashTreeRootWith(hh *ssz.Hasher) (err error) {
indx := hh.Index()
// Field (0) 'AttestedHeader'
if err = l.AttestedHeader.HashTreeRootWith(hh); err != nil {
return
}
// Field (1) 'NextSyncCommittee'
if err = l.NextSyncCommittee.HashTreeRootWith(hh); err != nil {
return
}
// Field (2) 'NextSyncCommitteeBranch'
{
if size := len(l.NextSyncCommitteeBranch); size != 5 {
err = ssz.ErrVectorLengthFn("--.NextSyncCommitteeBranch", size, 5)
return
}
subIndx := hh.Index()
for _, i := range l.NextSyncCommitteeBranch {
if len(i) != 32 {
err = ssz.ErrBytesLength
return
}
hh.Append(i)
}
hh.Merkleize(subIndx)
}
// Field (3) 'FinalizedHeader'
if err = l.FinalizedHeader.HashTreeRootWith(hh); err != nil {
return
}
// Field (4) 'FinalityBranch'
{
if size := len(l.FinalityBranch); size != 6 {
err = ssz.ErrVectorLengthFn("--.FinalityBranch", size, 6)
return
}
subIndx := hh.Index()
for _, i := range l.FinalityBranch {
if len(i) != 32 {
err = ssz.ErrBytesLength
return
}
hh.Append(i)
}
hh.Merkleize(subIndx)
}
// Field (5) 'SyncAggregate'
if err = l.SyncAggregate.HashTreeRootWith(hh); err != nil {
return
}
// Field (6) 'SignatureSlot'
hh.PutUint64(uint64(l.SignatureSlot))
hh.Merkleize(indx)
return
}
// MarshalSSZ ssz marshals the LightClientFinalityUpdateCapella object
func (l *LightClientFinalityUpdateCapella) MarshalSSZ() ([]byte, error) {
return ssz.MarshalSSZ(l)
}
// MarshalSSZTo ssz marshals the LightClientFinalityUpdateCapella object to a target array
func (l *LightClientFinalityUpdateCapella) MarshalSSZTo(buf []byte) (dst []byte, err error) {
dst = buf
offset := int(368)
// Offset (0) 'AttestedHeader'
dst = ssz.WriteOffset(dst, offset)
if l.AttestedHeader == nil {
l.AttestedHeader = new(LightClientHeaderCapella)
}
offset += l.AttestedHeader.SizeSSZ()
// Offset (1) 'FinalizedHeader'
dst = ssz.WriteOffset(dst, offset)
if l.FinalizedHeader == nil {
l.FinalizedHeader = new(LightClientHeaderCapella)
}
offset += l.FinalizedHeader.SizeSSZ()
// Field (2) 'FinalityBranch'
if size := len(l.FinalityBranch); size != 6 {
err = ssz.ErrVectorLengthFn("--.FinalityBranch", size, 6)
return
}
for ii := 0; ii < 6; ii++ {
if size := len(l.FinalityBranch[ii]); size != 32 {
err = ssz.ErrBytesLengthFn("--.FinalityBranch[ii]", size, 32)
return
}
dst = append(dst, l.FinalityBranch[ii]...)
}
// Field (3) 'SyncAggregate'
if l.SyncAggregate == nil {
l.SyncAggregate = new(SyncAggregate)
}
if dst, err = l.SyncAggregate.MarshalSSZTo(dst); err != nil {
return
}
// Field (4) 'SignatureSlot'
dst = ssz.MarshalUint64(dst, uint64(l.SignatureSlot))
// Field (0) 'AttestedHeader'
if dst, err = l.AttestedHeader.MarshalSSZTo(dst); err != nil {
return
}
// Field (1) 'FinalizedHeader'
if dst, err = l.FinalizedHeader.MarshalSSZTo(dst); err != nil {
return
}
return
}
// UnmarshalSSZ ssz unmarshals the LightClientFinalityUpdateCapella object
func (l *LightClientFinalityUpdateCapella) UnmarshalSSZ(buf []byte) error {
var err error
size := uint64(len(buf))
if size < 368 {
return ssz.ErrSize
}
tail := buf
var o0, o1 uint64
// Offset (0) 'AttestedHeader'
if o0 = ssz.ReadOffset(buf[0:4]); o0 > size {
return ssz.ErrOffset
}
if o0 != 368 {
return ssz.ErrInvalidVariableOffset
}
// Offset (1) 'FinalizedHeader'
if o1 = ssz.ReadOffset(buf[4:8]); o1 > size || o0 > o1 {
return ssz.ErrOffset
}
// Field (2) 'FinalityBranch'
l.FinalityBranch = make([][]byte, 6)
for ii := 0; ii < 6; ii++ {
if cap(l.FinalityBranch[ii]) == 0 {
l.FinalityBranch[ii] = make([]byte, 0, len(buf[8:200][ii*32:(ii+1)*32]))
}
l.FinalityBranch[ii] = append(l.FinalityBranch[ii], buf[8:200][ii*32:(ii+1)*32]...)
}
// Field (3) 'SyncAggregate'
if l.SyncAggregate == nil {
l.SyncAggregate = new(SyncAggregate)
}
if err = l.SyncAggregate.UnmarshalSSZ(buf[200:360]); err != nil {
return err
}
// Field (4) 'SignatureSlot'
l.SignatureSlot = github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.Slot(ssz.UnmarshallUint64(buf[360:368]))
// Field (0) 'AttestedHeader'
{
buf = tail[o0:o1]
if l.AttestedHeader == nil {
l.AttestedHeader = new(LightClientHeaderCapella)
}
if err = l.AttestedHeader.UnmarshalSSZ(buf); err != nil {
return err
}
}
// Field (1) 'FinalizedHeader'
{
buf = tail[o1:]
if l.FinalizedHeader == nil {
l.FinalizedHeader = new(LightClientHeaderCapella)
}
if err = l.FinalizedHeader.UnmarshalSSZ(buf); err != nil {
return err
}
}
return err
}
// SizeSSZ returns the ssz encoded size in bytes for the LightClientFinalityUpdateCapella object
func (l *LightClientFinalityUpdateCapella) SizeSSZ() (size int) {
size = 368
// Field (0) 'AttestedHeader'
if l.AttestedHeader == nil {
l.AttestedHeader = new(LightClientHeaderCapella)
}
size += l.AttestedHeader.SizeSSZ()
// Field (1) 'FinalizedHeader'
if l.FinalizedHeader == nil {
l.FinalizedHeader = new(LightClientHeaderCapella)
}
size += l.FinalizedHeader.SizeSSZ()
return
}
// HashTreeRoot ssz hashes the LightClientFinalityUpdateCapella object
func (l *LightClientFinalityUpdateCapella) HashTreeRoot() ([32]byte, error) {
return ssz.HashWithDefaultHasher(l)
}
// HashTreeRootWith ssz hashes the LightClientFinalityUpdateCapella object with a hasher
func (l *LightClientFinalityUpdateCapella) HashTreeRootWith(hh *ssz.Hasher) (err error) {
indx := hh.Index()
// Field (0) 'AttestedHeader'
if err = l.AttestedHeader.HashTreeRootWith(hh); err != nil {
return
}
// Field (1) 'FinalizedHeader'
if err = l.FinalizedHeader.HashTreeRootWith(hh); err != nil {
return
}
// Field (2) 'FinalityBranch'
{
if size := len(l.FinalityBranch); size != 6 {
err = ssz.ErrVectorLengthFn("--.FinalityBranch", size, 6)
return
}
subIndx := hh.Index()
for _, i := range l.FinalityBranch {
if len(i) != 32 {
err = ssz.ErrBytesLength
return
}
hh.Append(i)
}
hh.Merkleize(subIndx)
}
// Field (3) 'SyncAggregate'
if err = l.SyncAggregate.HashTreeRootWith(hh); err != nil {
return
}
// Field (4) 'SignatureSlot'
hh.PutUint64(uint64(l.SignatureSlot))
hh.Merkleize(indx)
return
}
// MarshalSSZ ssz marshals the LightClientOptimisticUpdateCapella object
func (l *LightClientOptimisticUpdateCapella) MarshalSSZ() ([]byte, error) {
return ssz.MarshalSSZ(l)
}
// MarshalSSZTo ssz marshals the LightClientOptimisticUpdateCapella object to a target array
func (l *LightClientOptimisticUpdateCapella) MarshalSSZTo(buf []byte) (dst []byte, err error) {
dst = buf
offset := int(172)
// Offset (0) 'AttestedHeader'
dst = ssz.WriteOffset(dst, offset)
if l.AttestedHeader == nil {
l.AttestedHeader = new(LightClientHeaderCapella)
}
offset += l.AttestedHeader.SizeSSZ()
// Field (1) 'SyncAggregate'
if l.SyncAggregate == nil {
l.SyncAggregate = new(SyncAggregate)
}
if dst, err = l.SyncAggregate.MarshalSSZTo(dst); err != nil {
return
}
// Field (2) 'SignatureSlot'
dst = ssz.MarshalUint64(dst, uint64(l.SignatureSlot))
// Field (0) 'AttestedHeader'
if dst, err = l.AttestedHeader.MarshalSSZTo(dst); err != nil {
return
}
return
}
// UnmarshalSSZ ssz unmarshals the LightClientOptimisticUpdateCapella object
func (l *LightClientOptimisticUpdateCapella) UnmarshalSSZ(buf []byte) error {
var err error
size := uint64(len(buf))
if size < 172 {
return ssz.ErrSize
}
tail := buf
var o0 uint64
// Offset (0) 'AttestedHeader'
if o0 = ssz.ReadOffset(buf[0:4]); o0 > size {
return ssz.ErrOffset
}
if o0 != 172 {
return ssz.ErrInvalidVariableOffset
}
// Field (1) 'SyncAggregate'
if l.SyncAggregate == nil {
l.SyncAggregate = new(SyncAggregate)
}
if err = l.SyncAggregate.UnmarshalSSZ(buf[4:164]); err != nil {
return err
}
// Field (2) 'SignatureSlot'
l.SignatureSlot = github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.Slot(ssz.UnmarshallUint64(buf[164:172]))
// Field (0) 'AttestedHeader'
{
buf = tail[o0:]
if l.AttestedHeader == nil {
l.AttestedHeader = new(LightClientHeaderCapella)
}
if err = l.AttestedHeader.UnmarshalSSZ(buf); err != nil {
return err
}
}
return err
}
// SizeSSZ returns the ssz encoded size in bytes for the LightClientOptimisticUpdateCapella object
func (l *LightClientOptimisticUpdateCapella) SizeSSZ() (size int) {
size = 172
// Field (0) 'AttestedHeader'
if l.AttestedHeader == nil {
l.AttestedHeader = new(LightClientHeaderCapella)
}
size += l.AttestedHeader.SizeSSZ()
return
}
// HashTreeRoot ssz hashes the LightClientOptimisticUpdateCapella object
func (l *LightClientOptimisticUpdateCapella) HashTreeRoot() ([32]byte, error) {
return ssz.HashWithDefaultHasher(l)
}
// HashTreeRootWith ssz hashes the LightClientOptimisticUpdateCapella object with a hasher
func (l *LightClientOptimisticUpdateCapella) HashTreeRootWith(hh *ssz.Hasher) (err error) {
indx := hh.Index()
// Field (0) 'AttestedHeader'
if err = l.AttestedHeader.HashTreeRootWith(hh); err != nil {
return
}
// Field (1) 'SyncAggregate'
if err = l.SyncAggregate.HashTreeRootWith(hh); err != nil {
return
}
// Field (2) 'SignatureSlot'
hh.PutUint64(uint64(l.SignatureSlot))
hh.Merkleize(indx)
return
}
// MarshalSSZ ssz marshals the BLSToExecutionChange object
func (b *BLSToExecutionChange) MarshalSSZ() ([]byte, error) {
return ssz.MarshalSSZ(b)

View File

@@ -1,5 +1,5 @@
// Code generated by fastssz. DO NOT EDIT.
// Hash: 4c3e6932bf84838e8de21e5c121c14d03cbccb051c3990d3b924932f531f4d30
// Hash: dc56f26fb2603482588d88426187e889583abce2eeb7556ac0dc1ebaa891c455
package eth
import (
@@ -3593,3 +3593,874 @@ func (b *BlobIdentifier) HashTreeRootWith(hh *ssz.Hasher) (err error) {
hh.Merkleize(indx)
return
}
// MarshalSSZ ssz marshals the LightClientHeaderDeneb object
func (l *LightClientHeaderDeneb) MarshalSSZ() ([]byte, error) {
return ssz.MarshalSSZ(l)
}
// MarshalSSZTo ssz marshals the LightClientHeaderDeneb object to a target array
func (l *LightClientHeaderDeneb) MarshalSSZTo(buf []byte) (dst []byte, err error) {
dst = buf
offset := int(244)
// Field (0) 'Beacon'
if l.Beacon == nil {
l.Beacon = new(BeaconBlockHeader)
}
if dst, err = l.Beacon.MarshalSSZTo(dst); err != nil {
return
}
// Offset (1) 'Execution'
dst = ssz.WriteOffset(dst, offset)
if l.Execution == nil {
l.Execution = new(v1.ExecutionPayloadHeaderDeneb)
}
offset += l.Execution.SizeSSZ()
// Field (2) 'ExecutionBranch'
if size := len(l.ExecutionBranch); size != 4 {
err = ssz.ErrVectorLengthFn("--.ExecutionBranch", size, 4)
return
}
for ii := 0; ii < 4; ii++ {
if size := len(l.ExecutionBranch[ii]); size != 32 {
err = ssz.ErrBytesLengthFn("--.ExecutionBranch[ii]", size, 32)
return
}
dst = append(dst, l.ExecutionBranch[ii]...)
}
// Field (1) 'Execution'
if dst, err = l.Execution.MarshalSSZTo(dst); err != nil {
return
}
return
}
// UnmarshalSSZ ssz unmarshals the LightClientHeaderDeneb object
func (l *LightClientHeaderDeneb) UnmarshalSSZ(buf []byte) error {
var err error
size := uint64(len(buf))
if size < 244 {
return ssz.ErrSize
}
tail := buf
var o1 uint64
// Field (0) 'Beacon'
if l.Beacon == nil {
l.Beacon = new(BeaconBlockHeader)
}
if err = l.Beacon.UnmarshalSSZ(buf[0:112]); err != nil {
return err
}
// Offset (1) 'Execution'
if o1 = ssz.ReadOffset(buf[112:116]); o1 > size {
return ssz.ErrOffset
}
if o1 != 244 {
return ssz.ErrInvalidVariableOffset
}
// Field (2) 'ExecutionBranch'
l.ExecutionBranch = make([][]byte, 4)
for ii := 0; ii < 4; ii++ {
if cap(l.ExecutionBranch[ii]) == 0 {
l.ExecutionBranch[ii] = make([]byte, 0, len(buf[116:244][ii*32:(ii+1)*32]))
}
l.ExecutionBranch[ii] = append(l.ExecutionBranch[ii], buf[116:244][ii*32:(ii+1)*32]...)
}
// Field (1) 'Execution'
{
buf = tail[o1:]
if l.Execution == nil {
l.Execution = new(v1.ExecutionPayloadHeaderDeneb)
}
if err = l.Execution.UnmarshalSSZ(buf); err != nil {
return err
}
}
return err
}
// SizeSSZ returns the ssz encoded size in bytes for the LightClientHeaderDeneb object
func (l *LightClientHeaderDeneb) SizeSSZ() (size int) {
size = 244
// Field (1) 'Execution'
if l.Execution == nil {
l.Execution = new(v1.ExecutionPayloadHeaderDeneb)
}
size += l.Execution.SizeSSZ()
return
}
// HashTreeRoot ssz hashes the LightClientHeaderDeneb object
func (l *LightClientHeaderDeneb) HashTreeRoot() ([32]byte, error) {
return ssz.HashWithDefaultHasher(l)
}
// HashTreeRootWith ssz hashes the LightClientHeaderDeneb object with a hasher
func (l *LightClientHeaderDeneb) HashTreeRootWith(hh *ssz.Hasher) (err error) {
indx := hh.Index()
// Field (0) 'Beacon'
if err = l.Beacon.HashTreeRootWith(hh); err != nil {
return
}
// Field (1) 'Execution'
if err = l.Execution.HashTreeRootWith(hh); err != nil {
return
}
// Field (2) 'ExecutionBranch'
{
if size := len(l.ExecutionBranch); size != 4 {
err = ssz.ErrVectorLengthFn("--.ExecutionBranch", size, 4)
return
}
subIndx := hh.Index()
for _, i := range l.ExecutionBranch {
if len(i) != 32 {
err = ssz.ErrBytesLength
return
}
hh.Append(i)
}
hh.Merkleize(subIndx)
}
hh.Merkleize(indx)
return
}
// MarshalSSZ ssz marshals the LightClientBootstrapDeneb object
func (l *LightClientBootstrapDeneb) MarshalSSZ() ([]byte, error) {
return ssz.MarshalSSZ(l)
}
// MarshalSSZTo ssz marshals the LightClientBootstrapDeneb object to a target array
func (l *LightClientBootstrapDeneb) MarshalSSZTo(buf []byte) (dst []byte, err error) {
dst = buf
offset := int(24788)
// Offset (0) 'Header'
dst = ssz.WriteOffset(dst, offset)
if l.Header == nil {
l.Header = new(LightClientHeaderDeneb)
}
offset += l.Header.SizeSSZ()
// Field (1) 'CurrentSyncCommittee'
if l.CurrentSyncCommittee == nil {
l.CurrentSyncCommittee = new(SyncCommittee)
}
if dst, err = l.CurrentSyncCommittee.MarshalSSZTo(dst); err != nil {
return
}
// Field (2) 'CurrentSyncCommitteeBranch'
if size := len(l.CurrentSyncCommitteeBranch); size != 5 {
err = ssz.ErrVectorLengthFn("--.CurrentSyncCommitteeBranch", size, 5)
return
}
for ii := 0; ii < 5; ii++ {
if size := len(l.CurrentSyncCommitteeBranch[ii]); size != 32 {
err = ssz.ErrBytesLengthFn("--.CurrentSyncCommitteeBranch[ii]", size, 32)
return
}
dst = append(dst, l.CurrentSyncCommitteeBranch[ii]...)
}
// Field (0) 'Header'
if dst, err = l.Header.MarshalSSZTo(dst); err != nil {
return
}
return
}
// UnmarshalSSZ ssz unmarshals the LightClientBootstrapDeneb object
func (l *LightClientBootstrapDeneb) UnmarshalSSZ(buf []byte) error {
var err error
size := uint64(len(buf))
if size < 24788 {
return ssz.ErrSize
}
tail := buf
var o0 uint64
// Offset (0) 'Header'
if o0 = ssz.ReadOffset(buf[0:4]); o0 > size {
return ssz.ErrOffset
}
if o0 != 24788 {
return ssz.ErrInvalidVariableOffset
}
// Field (1) 'CurrentSyncCommittee'
if l.CurrentSyncCommittee == nil {
l.CurrentSyncCommittee = new(SyncCommittee)
}
if err = l.CurrentSyncCommittee.UnmarshalSSZ(buf[4:24628]); err != nil {
return err
}
// Field (2) 'CurrentSyncCommitteeBranch'
l.CurrentSyncCommitteeBranch = make([][]byte, 5)
for ii := 0; ii < 5; ii++ {
if cap(l.CurrentSyncCommitteeBranch[ii]) == 0 {
l.CurrentSyncCommitteeBranch[ii] = make([]byte, 0, len(buf[24628:24788][ii*32:(ii+1)*32]))
}
l.CurrentSyncCommitteeBranch[ii] = append(l.CurrentSyncCommitteeBranch[ii], buf[24628:24788][ii*32:(ii+1)*32]...)
}
// Field (0) 'Header'
{
buf = tail[o0:]
if l.Header == nil {
l.Header = new(LightClientHeaderDeneb)
}
if err = l.Header.UnmarshalSSZ(buf); err != nil {
return err
}
}
return err
}
// SizeSSZ returns the ssz encoded size in bytes for the LightClientBootstrapDeneb object
func (l *LightClientBootstrapDeneb) SizeSSZ() (size int) {
size = 24788
// Field (0) 'Header'
if l.Header == nil {
l.Header = new(LightClientHeaderDeneb)
}
size += l.Header.SizeSSZ()
return
}
// HashTreeRoot ssz hashes the LightClientBootstrapDeneb object
func (l *LightClientBootstrapDeneb) HashTreeRoot() ([32]byte, error) {
return ssz.HashWithDefaultHasher(l)
}
// HashTreeRootWith ssz hashes the LightClientBootstrapDeneb object with a hasher
func (l *LightClientBootstrapDeneb) HashTreeRootWith(hh *ssz.Hasher) (err error) {
indx := hh.Index()
// Field (0) 'Header'
if err = l.Header.HashTreeRootWith(hh); err != nil {
return
}
// Field (1) 'CurrentSyncCommittee'
if err = l.CurrentSyncCommittee.HashTreeRootWith(hh); err != nil {
return
}
// Field (2) 'CurrentSyncCommitteeBranch'
{
if size := len(l.CurrentSyncCommitteeBranch); size != 5 {
err = ssz.ErrVectorLengthFn("--.CurrentSyncCommitteeBranch", size, 5)
return
}
subIndx := hh.Index()
for _, i := range l.CurrentSyncCommitteeBranch {
if len(i) != 32 {
err = ssz.ErrBytesLength
return
}
hh.Append(i)
}
hh.Merkleize(subIndx)
}
hh.Merkleize(indx)
return
}
// MarshalSSZ ssz marshals the LightClientUpdateDeneb object
func (l *LightClientUpdateDeneb) MarshalSSZ() ([]byte, error) {
return ssz.MarshalSSZ(l)
}
// MarshalSSZTo ssz marshals the LightClientUpdateDeneb object to a target array
func (l *LightClientUpdateDeneb) MarshalSSZTo(buf []byte) (dst []byte, err error) {
dst = buf
offset := int(25152)
// Offset (0) 'AttestedHeader'
dst = ssz.WriteOffset(dst, offset)
if l.AttestedHeader == nil {
l.AttestedHeader = new(LightClientHeaderDeneb)
}
offset += l.AttestedHeader.SizeSSZ()
// Field (1) 'NextSyncCommittee'
if l.NextSyncCommittee == nil {
l.NextSyncCommittee = new(SyncCommittee)
}
if dst, err = l.NextSyncCommittee.MarshalSSZTo(dst); err != nil {
return
}
// Field (2) 'NextSyncCommitteeBranch'
if size := len(l.NextSyncCommitteeBranch); size != 5 {
err = ssz.ErrVectorLengthFn("--.NextSyncCommitteeBranch", size, 5)
return
}
for ii := 0; ii < 5; ii++ {
if size := len(l.NextSyncCommitteeBranch[ii]); size != 32 {
err = ssz.ErrBytesLengthFn("--.NextSyncCommitteeBranch[ii]", size, 32)
return
}
dst = append(dst, l.NextSyncCommitteeBranch[ii]...)
}
// Offset (3) 'FinalizedHeader'
dst = ssz.WriteOffset(dst, offset)
if l.FinalizedHeader == nil {
l.FinalizedHeader = new(LightClientHeaderDeneb)
}
offset += l.FinalizedHeader.SizeSSZ()
// Field (4) 'FinalityBranch'
if size := len(l.FinalityBranch); size != 6 {
err = ssz.ErrVectorLengthFn("--.FinalityBranch", size, 6)
return
}
for ii := 0; ii < 6; ii++ {
if size := len(l.FinalityBranch[ii]); size != 32 {
err = ssz.ErrBytesLengthFn("--.FinalityBranch[ii]", size, 32)
return
}
dst = append(dst, l.FinalityBranch[ii]...)
}
// Field (5) 'SyncAggregate'
if l.SyncAggregate == nil {
l.SyncAggregate = new(SyncAggregate)
}
if dst, err = l.SyncAggregate.MarshalSSZTo(dst); err != nil {
return
}
// Field (6) 'SignatureSlot'
dst = ssz.MarshalUint64(dst, uint64(l.SignatureSlot))
// Field (0) 'AttestedHeader'
if dst, err = l.AttestedHeader.MarshalSSZTo(dst); err != nil {
return
}
// Field (3) 'FinalizedHeader'
if dst, err = l.FinalizedHeader.MarshalSSZTo(dst); err != nil {
return
}
return
}
// UnmarshalSSZ ssz unmarshals the LightClientUpdateDeneb object
func (l *LightClientUpdateDeneb) UnmarshalSSZ(buf []byte) error {
var err error
size := uint64(len(buf))
if size < 25152 {
return ssz.ErrSize
}
tail := buf
var o0, o3 uint64
// Offset (0) 'AttestedHeader'
if o0 = ssz.ReadOffset(buf[0:4]); o0 > size {
return ssz.ErrOffset
}
if o0 != 25152 {
return ssz.ErrInvalidVariableOffset
}
// Field (1) 'NextSyncCommittee'
if l.NextSyncCommittee == nil {
l.NextSyncCommittee = new(SyncCommittee)
}
if err = l.NextSyncCommittee.UnmarshalSSZ(buf[4:24628]); err != nil {
return err
}
// Field (2) 'NextSyncCommitteeBranch'
l.NextSyncCommitteeBranch = make([][]byte, 5)
for ii := 0; ii < 5; ii++ {
if cap(l.NextSyncCommitteeBranch[ii]) == 0 {
l.NextSyncCommitteeBranch[ii] = make([]byte, 0, len(buf[24628:24788][ii*32:(ii+1)*32]))
}
l.NextSyncCommitteeBranch[ii] = append(l.NextSyncCommitteeBranch[ii], buf[24628:24788][ii*32:(ii+1)*32]...)
}
// Offset (3) 'FinalizedHeader'
if o3 = ssz.ReadOffset(buf[24788:24792]); o3 > size || o0 > o3 {
return ssz.ErrOffset
}
// Field (4) 'FinalityBranch'
l.FinalityBranch = make([][]byte, 6)
for ii := 0; ii < 6; ii++ {
if cap(l.FinalityBranch[ii]) == 0 {
l.FinalityBranch[ii] = make([]byte, 0, len(buf[24792:24984][ii*32:(ii+1)*32]))
}
l.FinalityBranch[ii] = append(l.FinalityBranch[ii], buf[24792:24984][ii*32:(ii+1)*32]...)
}
// Field (5) 'SyncAggregate'
if l.SyncAggregate == nil {
l.SyncAggregate = new(SyncAggregate)
}
if err = l.SyncAggregate.UnmarshalSSZ(buf[24984:25144]); err != nil {
return err
}
// Field (6) 'SignatureSlot'
l.SignatureSlot = github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.Slot(ssz.UnmarshallUint64(buf[25144:25152]))
// Field (0) 'AttestedHeader'
{
buf = tail[o0:o3]
if l.AttestedHeader == nil {
l.AttestedHeader = new(LightClientHeaderDeneb)
}
if err = l.AttestedHeader.UnmarshalSSZ(buf); err != nil {
return err
}
}
// Field (3) 'FinalizedHeader'
{
buf = tail[o3:]
if l.FinalizedHeader == nil {
l.FinalizedHeader = new(LightClientHeaderDeneb)
}
if err = l.FinalizedHeader.UnmarshalSSZ(buf); err != nil {
return err
}
}
return err
}
// SizeSSZ returns the ssz encoded size in bytes for the LightClientUpdateDeneb object
func (l *LightClientUpdateDeneb) SizeSSZ() (size int) {
size = 25152
// Field (0) 'AttestedHeader'
if l.AttestedHeader == nil {
l.AttestedHeader = new(LightClientHeaderDeneb)
}
size += l.AttestedHeader.SizeSSZ()
// Field (3) 'FinalizedHeader'
if l.FinalizedHeader == nil {
l.FinalizedHeader = new(LightClientHeaderDeneb)
}
size += l.FinalizedHeader.SizeSSZ()
return
}
// HashTreeRoot ssz hashes the LightClientUpdateDeneb object
func (l *LightClientUpdateDeneb) HashTreeRoot() ([32]byte, error) {
return ssz.HashWithDefaultHasher(l)
}
// HashTreeRootWith ssz hashes the LightClientUpdateDeneb object with a hasher
func (l *LightClientUpdateDeneb) HashTreeRootWith(hh *ssz.Hasher) (err error) {
indx := hh.Index()
// Field (0) 'AttestedHeader'
if err = l.AttestedHeader.HashTreeRootWith(hh); err != nil {
return
}
// Field (1) 'NextSyncCommittee'
if err = l.NextSyncCommittee.HashTreeRootWith(hh); err != nil {
return
}
// Field (2) 'NextSyncCommitteeBranch'
{
if size := len(l.NextSyncCommitteeBranch); size != 5 {
err = ssz.ErrVectorLengthFn("--.NextSyncCommitteeBranch", size, 5)
return
}
subIndx := hh.Index()
for _, i := range l.NextSyncCommitteeBranch {
if len(i) != 32 {
err = ssz.ErrBytesLength
return
}
hh.Append(i)
}
hh.Merkleize(subIndx)
}
// Field (3) 'FinalizedHeader'
if err = l.FinalizedHeader.HashTreeRootWith(hh); err != nil {
return
}
// Field (4) 'FinalityBranch'
{
if size := len(l.FinalityBranch); size != 6 {
err = ssz.ErrVectorLengthFn("--.FinalityBranch", size, 6)
return
}
subIndx := hh.Index()
for _, i := range l.FinalityBranch {
if len(i) != 32 {
err = ssz.ErrBytesLength
return
}
hh.Append(i)
}
hh.Merkleize(subIndx)
}
// Field (5) 'SyncAggregate'
if err = l.SyncAggregate.HashTreeRootWith(hh); err != nil {
return
}
// Field (6) 'SignatureSlot'
hh.PutUint64(uint64(l.SignatureSlot))
hh.Merkleize(indx)
return
}
// MarshalSSZ ssz marshals the LightClientFinalityUpdateDeneb object
func (l *LightClientFinalityUpdateDeneb) MarshalSSZ() ([]byte, error) {
return ssz.MarshalSSZ(l)
}
// MarshalSSZTo ssz marshals the LightClientFinalityUpdateDeneb object to a target array
func (l *LightClientFinalityUpdateDeneb) MarshalSSZTo(buf []byte) (dst []byte, err error) {
dst = buf
offset := int(368)
// Offset (0) 'AttestedHeader'
dst = ssz.WriteOffset(dst, offset)
if l.AttestedHeader == nil {
l.AttestedHeader = new(LightClientHeaderDeneb)
}
offset += l.AttestedHeader.SizeSSZ()
// Offset (1) 'FinalizedHeader'
dst = ssz.WriteOffset(dst, offset)
if l.FinalizedHeader == nil {
l.FinalizedHeader = new(LightClientHeaderDeneb)
}
offset += l.FinalizedHeader.SizeSSZ()
// Field (2) 'FinalityBranch'
if size := len(l.FinalityBranch); size != 6 {
err = ssz.ErrVectorLengthFn("--.FinalityBranch", size, 6)
return
}
for ii := 0; ii < 6; ii++ {
if size := len(l.FinalityBranch[ii]); size != 32 {
err = ssz.ErrBytesLengthFn("--.FinalityBranch[ii]", size, 32)
return
}
dst = append(dst, l.FinalityBranch[ii]...)
}
// Field (3) 'SyncAggregate'
if l.SyncAggregate == nil {
l.SyncAggregate = new(SyncAggregate)
}
if dst, err = l.SyncAggregate.MarshalSSZTo(dst); err != nil {
return
}
// Field (4) 'SignatureSlot'
dst = ssz.MarshalUint64(dst, uint64(l.SignatureSlot))
// Field (0) 'AttestedHeader'
if dst, err = l.AttestedHeader.MarshalSSZTo(dst); err != nil {
return
}
// Field (1) 'FinalizedHeader'
if dst, err = l.FinalizedHeader.MarshalSSZTo(dst); err != nil {
return
}
return
}
// UnmarshalSSZ ssz unmarshals the LightClientFinalityUpdateDeneb object
func (l *LightClientFinalityUpdateDeneb) UnmarshalSSZ(buf []byte) error {
var err error
size := uint64(len(buf))
if size < 368 {
return ssz.ErrSize
}
tail := buf
var o0, o1 uint64
// Offset (0) 'AttestedHeader'
if o0 = ssz.ReadOffset(buf[0:4]); o0 > size {
return ssz.ErrOffset
}
if o0 != 368 {
return ssz.ErrInvalidVariableOffset
}
// Offset (1) 'FinalizedHeader'
if o1 = ssz.ReadOffset(buf[4:8]); o1 > size || o0 > o1 {
return ssz.ErrOffset
}
// Field (2) 'FinalityBranch'
l.FinalityBranch = make([][]byte, 6)
for ii := 0; ii < 6; ii++ {
if cap(l.FinalityBranch[ii]) == 0 {
l.FinalityBranch[ii] = make([]byte, 0, len(buf[8:200][ii*32:(ii+1)*32]))
}
l.FinalityBranch[ii] = append(l.FinalityBranch[ii], buf[8:200][ii*32:(ii+1)*32]...)
}
// Field (3) 'SyncAggregate'
if l.SyncAggregate == nil {
l.SyncAggregate = new(SyncAggregate)
}
if err = l.SyncAggregate.UnmarshalSSZ(buf[200:360]); err != nil {
return err
}
// Field (4) 'SignatureSlot'
l.SignatureSlot = github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.Slot(ssz.UnmarshallUint64(buf[360:368]))
// Field (0) 'AttestedHeader'
{
buf = tail[o0:o1]
if l.AttestedHeader == nil {
l.AttestedHeader = new(LightClientHeaderDeneb)
}
if err = l.AttestedHeader.UnmarshalSSZ(buf); err != nil {
return err
}
}
// Field (1) 'FinalizedHeader'
{
buf = tail[o1:]
if l.FinalizedHeader == nil {
l.FinalizedHeader = new(LightClientHeaderDeneb)
}
if err = l.FinalizedHeader.UnmarshalSSZ(buf); err != nil {
return err
}
}
return err
}
// SizeSSZ returns the ssz encoded size in bytes for the LightClientFinalityUpdateDeneb object
func (l *LightClientFinalityUpdateDeneb) SizeSSZ() (size int) {
size = 368
// Field (0) 'AttestedHeader'
if l.AttestedHeader == nil {
l.AttestedHeader = new(LightClientHeaderDeneb)
}
size += l.AttestedHeader.SizeSSZ()
// Field (1) 'FinalizedHeader'
if l.FinalizedHeader == nil {
l.FinalizedHeader = new(LightClientHeaderDeneb)
}
size += l.FinalizedHeader.SizeSSZ()
return
}
// HashTreeRoot ssz hashes the LightClientFinalityUpdateDeneb object
func (l *LightClientFinalityUpdateDeneb) HashTreeRoot() ([32]byte, error) {
return ssz.HashWithDefaultHasher(l)
}
// HashTreeRootWith ssz hashes the LightClientFinalityUpdateDeneb object with a hasher
func (l *LightClientFinalityUpdateDeneb) HashTreeRootWith(hh *ssz.Hasher) (err error) {
indx := hh.Index()
// Field (0) 'AttestedHeader'
if err = l.AttestedHeader.HashTreeRootWith(hh); err != nil {
return
}
// Field (1) 'FinalizedHeader'
if err = l.FinalizedHeader.HashTreeRootWith(hh); err != nil {
return
}
// Field (2) 'FinalityBranch'
{
if size := len(l.FinalityBranch); size != 6 {
err = ssz.ErrVectorLengthFn("--.FinalityBranch", size, 6)
return
}
subIndx := hh.Index()
for _, i := range l.FinalityBranch {
if len(i) != 32 {
err = ssz.ErrBytesLength
return
}
hh.Append(i)
}
hh.Merkleize(subIndx)
}
// Field (3) 'SyncAggregate'
if err = l.SyncAggregate.HashTreeRootWith(hh); err != nil {
return
}
// Field (4) 'SignatureSlot'
hh.PutUint64(uint64(l.SignatureSlot))
hh.Merkleize(indx)
return
}
// MarshalSSZ ssz marshals the LightClientOptimisticUpdateDeneb object
func (l *LightClientOptimisticUpdateDeneb) MarshalSSZ() ([]byte, error) {
return ssz.MarshalSSZ(l)
}
// MarshalSSZTo ssz marshals the LightClientOptimisticUpdateDeneb object to a target array
func (l *LightClientOptimisticUpdateDeneb) MarshalSSZTo(buf []byte) (dst []byte, err error) {
dst = buf
offset := int(172)
// Offset (0) 'AttestedHeader'
dst = ssz.WriteOffset(dst, offset)
if l.AttestedHeader == nil {
l.AttestedHeader = new(LightClientHeaderDeneb)
}
offset += l.AttestedHeader.SizeSSZ()
// Field (1) 'SyncAggregate'
if l.SyncAggregate == nil {
l.SyncAggregate = new(SyncAggregate)
}
if dst, err = l.SyncAggregate.MarshalSSZTo(dst); err != nil {
return
}
// Field (2) 'SignatureSlot'
dst = ssz.MarshalUint64(dst, uint64(l.SignatureSlot))
// Field (0) 'AttestedHeader'
if dst, err = l.AttestedHeader.MarshalSSZTo(dst); err != nil {
return
}
return
}
// UnmarshalSSZ ssz unmarshals the LightClientOptimisticUpdateDeneb object
func (l *LightClientOptimisticUpdateDeneb) UnmarshalSSZ(buf []byte) error {
var err error
size := uint64(len(buf))
if size < 172 {
return ssz.ErrSize
}
tail := buf
var o0 uint64
// Offset (0) 'AttestedHeader'
if o0 = ssz.ReadOffset(buf[0:4]); o0 > size {
return ssz.ErrOffset
}
if o0 != 172 {
return ssz.ErrInvalidVariableOffset
}
// Field (1) 'SyncAggregate'
if l.SyncAggregate == nil {
l.SyncAggregate = new(SyncAggregate)
}
if err = l.SyncAggregate.UnmarshalSSZ(buf[4:164]); err != nil {
return err
}
// Field (2) 'SignatureSlot'
l.SignatureSlot = github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.Slot(ssz.UnmarshallUint64(buf[164:172]))
// Field (0) 'AttestedHeader'
{
buf = tail[o0:]
if l.AttestedHeader == nil {
l.AttestedHeader = new(LightClientHeaderDeneb)
}
if err = l.AttestedHeader.UnmarshalSSZ(buf); err != nil {
return err
}
}
return err
}
// SizeSSZ returns the ssz encoded size in bytes for the LightClientOptimisticUpdateDeneb object
func (l *LightClientOptimisticUpdateDeneb) SizeSSZ() (size int) {
size = 172
// Field (0) 'AttestedHeader'
if l.AttestedHeader == nil {
l.AttestedHeader = new(LightClientHeaderDeneb)
}
size += l.AttestedHeader.SizeSSZ()
return
}
// HashTreeRoot ssz hashes the LightClientOptimisticUpdateDeneb object
func (l *LightClientOptimisticUpdateDeneb) HashTreeRoot() ([32]byte, error) {
return ssz.HashWithDefaultHasher(l)
}
// HashTreeRootWith ssz hashes the LightClientOptimisticUpdateDeneb object with a hasher
func (l *LightClientOptimisticUpdateDeneb) HashTreeRootWith(hh *ssz.Hasher) (err error) {
indx := hh.Index()
// Field (0) 'AttestedHeader'
if err = l.AttestedHeader.HashTreeRootWith(hh); err != nil {
return
}
// Field (1) 'SyncAggregate'
if err = l.SyncAggregate.HashTreeRootWith(hh); err != nil {
return
}
// Field (2) 'SignatureSlot'
hh.PutUint64(uint64(l.SignatureSlot))
hh.Merkleize(indx)
return
}

View File

@@ -1,5 +1,5 @@
// Code generated by fastssz. DO NOT EDIT.
// Hash: 6d900c40d922575c27ef51a244f7bf935f56aa440017288a3405a3025d7750a6
// Hash: 3a2dbf56ebf4e81fbf961840a4cd2addac9047b17c12bad04e60879df5b69277
package eth
import (
@@ -862,6 +862,215 @@ func (s *SignedBeaconBlockContentsElectra) HashTreeRootWith(hh *ssz.Hasher) (err
return
}
// MarshalSSZ ssz marshals the BeaconBlockContentsElectra object
func (b *BeaconBlockContentsElectra) MarshalSSZ() ([]byte, error) {
return ssz.MarshalSSZ(b)
}
// MarshalSSZTo ssz marshals the BeaconBlockContentsElectra object to a target array
func (b *BeaconBlockContentsElectra) MarshalSSZTo(buf []byte) (dst []byte, err error) {
dst = buf
offset := int(12)
// Offset (0) 'Block'
dst = ssz.WriteOffset(dst, offset)
if b.Block == nil {
b.Block = new(BeaconBlockElectra)
}
offset += b.Block.SizeSSZ()
// Offset (1) 'KzgProofs'
dst = ssz.WriteOffset(dst, offset)
offset += len(b.KzgProofs) * 48
// Offset (2) 'Blobs'
dst = ssz.WriteOffset(dst, offset)
offset += len(b.Blobs) * 131072
// Field (0) 'Block'
if dst, err = b.Block.MarshalSSZTo(dst); err != nil {
return
}
// Field (1) 'KzgProofs'
if size := len(b.KzgProofs); size > 4096 {
err = ssz.ErrListTooBigFn("--.KzgProofs", size, 4096)
return
}
for ii := 0; ii < len(b.KzgProofs); ii++ {
if size := len(b.KzgProofs[ii]); size != 48 {
err = ssz.ErrBytesLengthFn("--.KzgProofs[ii]", size, 48)
return
}
dst = append(dst, b.KzgProofs[ii]...)
}
// Field (2) 'Blobs'
if size := len(b.Blobs); size > 4096 {
err = ssz.ErrListTooBigFn("--.Blobs", size, 4096)
return
}
for ii := 0; ii < len(b.Blobs); ii++ {
if size := len(b.Blobs[ii]); size != 131072 {
err = ssz.ErrBytesLengthFn("--.Blobs[ii]", size, 131072)
return
}
dst = append(dst, b.Blobs[ii]...)
}
return
}
// UnmarshalSSZ ssz unmarshals the BeaconBlockContentsElectra object
func (b *BeaconBlockContentsElectra) UnmarshalSSZ(buf []byte) error {
var err error
size := uint64(len(buf))
if size < 12 {
return ssz.ErrSize
}
tail := buf
var o0, o1, o2 uint64
// Offset (0) 'Block'
if o0 = ssz.ReadOffset(buf[0:4]); o0 > size {
return ssz.ErrOffset
}
if o0 != 12 {
return ssz.ErrInvalidVariableOffset
}
// Offset (1) 'KzgProofs'
if o1 = ssz.ReadOffset(buf[4:8]); o1 > size || o0 > o1 {
return ssz.ErrOffset
}
// Offset (2) 'Blobs'
if o2 = ssz.ReadOffset(buf[8:12]); o2 > size || o1 > o2 {
return ssz.ErrOffset
}
// Field (0) 'Block'
{
buf = tail[o0:o1]
if b.Block == nil {
b.Block = new(BeaconBlockElectra)
}
if err = b.Block.UnmarshalSSZ(buf); err != nil {
return err
}
}
// Field (1) 'KzgProofs'
{
buf = tail[o1:o2]
num, err := ssz.DivideInt2(len(buf), 48, 4096)
if err != nil {
return err
}
b.KzgProofs = make([][]byte, num)
for ii := 0; ii < num; ii++ {
if cap(b.KzgProofs[ii]) == 0 {
b.KzgProofs[ii] = make([]byte, 0, len(buf[ii*48:(ii+1)*48]))
}
b.KzgProofs[ii] = append(b.KzgProofs[ii], buf[ii*48:(ii+1)*48]...)
}
}
// Field (2) 'Blobs'
{
buf = tail[o2:]
num, err := ssz.DivideInt2(len(buf), 131072, 4096)
if err != nil {
return err
}
b.Blobs = make([][]byte, num)
for ii := 0; ii < num; ii++ {
if cap(b.Blobs[ii]) == 0 {
b.Blobs[ii] = make([]byte, 0, len(buf[ii*131072:(ii+1)*131072]))
}
b.Blobs[ii] = append(b.Blobs[ii], buf[ii*131072:(ii+1)*131072]...)
}
}
return err
}
// SizeSSZ returns the ssz encoded size in bytes for the BeaconBlockContentsElectra object
func (b *BeaconBlockContentsElectra) SizeSSZ() (size int) {
size = 12
// Field (0) 'Block'
if b.Block == nil {
b.Block = new(BeaconBlockElectra)
}
size += b.Block.SizeSSZ()
// Field (1) 'KzgProofs'
size += len(b.KzgProofs) * 48
// Field (2) 'Blobs'
size += len(b.Blobs) * 131072
return
}
// HashTreeRoot ssz hashes the BeaconBlockContentsElectra object
func (b *BeaconBlockContentsElectra) HashTreeRoot() ([32]byte, error) {
return ssz.HashWithDefaultHasher(b)
}
// HashTreeRootWith ssz hashes the BeaconBlockContentsElectra object with a hasher
func (b *BeaconBlockContentsElectra) HashTreeRootWith(hh *ssz.Hasher) (err error) {
indx := hh.Index()
// Field (0) 'Block'
if err = b.Block.HashTreeRootWith(hh); err != nil {
return
}
// Field (1) 'KzgProofs'
{
if size := len(b.KzgProofs); size > 4096 {
err = ssz.ErrListTooBigFn("--.KzgProofs", size, 4096)
return
}
subIndx := hh.Index()
for _, i := range b.KzgProofs {
if len(i) != 48 {
err = ssz.ErrBytesLength
return
}
hh.PutBytes(i)
}
numItems := uint64(len(b.KzgProofs))
hh.MerkleizeWithMixin(subIndx, numItems, 4096)
}
// Field (2) 'Blobs'
{
if size := len(b.Blobs); size > 4096 {
err = ssz.ErrListTooBigFn("--.Blobs", size, 4096)
return
}
subIndx := hh.Index()
for _, i := range b.Blobs {
if len(i) != 131072 {
err = ssz.ErrBytesLength
return
}
hh.PutBytes(i)
}
numItems := uint64(len(b.Blobs))
hh.MerkleizeWithMixin(subIndx, numItems, 4096)
}
hh.Merkleize(indx)
return
}
// MarshalSSZ ssz marshals the SignedBeaconBlockElectra object
func (s *SignedBeaconBlockElectra) MarshalSSZ() ([]byte, error) {
return ssz.MarshalSSZ(s)

1759
proto/prysm/v1alpha1/light_client.pb.go generated Executable file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,134 @@
// Copyright 2024 Prysmatic Labs.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
syntax = "proto3";
package ethereum.eth.v1alpha1;
import "proto/eth/ext/options.proto";
import "proto/prysm/v1alpha1/beacon_block.proto";
import "proto/engine/v1/execution_engine.proto";
import "proto/prysm/v1alpha1/beacon_state.proto";
option csharp_namespace = "Ethereum.Eth.V1alpha1";
option go_package = "github.com/prysmaticlabs/prysm/v5/proto/eth/v1alpha1;eth";
option java_multiple_files = true;
option java_outer_classname = "LightClientProto";
option java_package = "org.ethereum.eth.v1alpha1";
option php_namespace = "Ethereum\\Eth\\v1alpha1";
message LightClientHeaderAltair {
BeaconBlockHeader beacon = 1;
}
message LightClientHeaderCapella {
BeaconBlockHeader beacon = 1;
ethereum.engine.v1.ExecutionPayloadHeaderCapella execution = 2;
repeated bytes execution_branch = 3 [(ethereum.eth.ext.ssz_size) = "4,32"];
}
message LightClientHeaderDeneb {
BeaconBlockHeader beacon = 1;
ethereum.engine.v1.ExecutionPayloadHeaderDeneb execution = 2;
repeated bytes execution_branch = 3 [(ethereum.eth.ext.ssz_size) = "4,32"];
}
message LightClientBootstrapAltair {
LightClientHeaderAltair header = 1;
SyncCommittee current_sync_committee = 2;
repeated bytes current_sync_committee_branch = 3 [(ethereum.eth.ext.ssz_size) = "5,32"];
}
message LightClientBootstrapCapella {
LightClientHeaderCapella header = 1;
SyncCommittee current_sync_committee = 2;
repeated bytes current_sync_committee_branch = 3 [(ethereum.eth.ext.ssz_size) = "5,32"];
}
message LightClientBootstrapDeneb {
LightClientHeaderDeneb header = 1;
SyncCommittee current_sync_committee = 2;
repeated bytes current_sync_committee_branch = 3 [(ethereum.eth.ext.ssz_size) = "5,32"];
}
message LightClientUpdateAltair {
LightClientHeaderAltair attested_header = 1;
SyncCommittee next_sync_committee = 2;
repeated bytes next_sync_committee_branch = 3 [(ethereum.eth.ext.ssz_size) = "5,32"];
LightClientHeaderAltair finalized_header = 4;
repeated bytes finality_branch = 5 [(ethereum.eth.ext.ssz_size) = "6,32"];
SyncAggregate sync_aggregate = 6;
uint64 signature_slot = 7 [(ethereum.eth.ext.cast_type) = "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives.Slot"];
}
message LightClientUpdateCapella {
LightClientHeaderCapella attested_header = 1;
SyncCommittee next_sync_committee = 2;
repeated bytes next_sync_committee_branch = 3 [(ethereum.eth.ext.ssz_size) = "5,32"];
LightClientHeaderCapella finalized_header = 4;
repeated bytes finality_branch = 5 [(ethereum.eth.ext.ssz_size) = "6,32"];
SyncAggregate sync_aggregate = 6;
uint64 signature_slot = 7 [(ethereum.eth.ext.cast_type) = "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives.Slot"];
}
message LightClientUpdateDeneb {
LightClientHeaderDeneb attested_header = 1;
SyncCommittee next_sync_committee = 2;
repeated bytes next_sync_committee_branch = 3 [(ethereum.eth.ext.ssz_size) = "5,32"];
LightClientHeaderDeneb finalized_header = 4;
repeated bytes finality_branch = 5 [(ethereum.eth.ext.ssz_size) = "6,32"];
SyncAggregate sync_aggregate = 6;
uint64 signature_slot = 7 [(ethereum.eth.ext.cast_type) = "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives.Slot"];
}
message LightClientFinalityUpdateAltair {
LightClientHeaderAltair attested_header = 1;
LightClientHeaderAltair finalized_header = 2;
repeated bytes finality_branch = 3 [(ethereum.eth.ext.ssz_size) = "6,32"];
SyncAggregate sync_aggregate = 4;
uint64 signature_slot = 5 [(ethereum.eth.ext.cast_type) = "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives.Slot"];
}
message LightClientFinalityUpdateCapella {
LightClientHeaderCapella attested_header = 1;
LightClientHeaderCapella finalized_header = 2;
repeated bytes finality_branch = 3 [(ethereum.eth.ext.ssz_size) = "6,32"];
SyncAggregate sync_aggregate = 4;
uint64 signature_slot = 5 [(ethereum.eth.ext.cast_type) = "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives.Slot"];
}
message LightClientFinalityUpdateDeneb {
LightClientHeaderDeneb attested_header = 1;
LightClientHeaderDeneb finalized_header = 2;
repeated bytes finality_branch = 3 [(ethereum.eth.ext.ssz_size) = "6,32"];
SyncAggregate sync_aggregate = 4;
uint64 signature_slot = 5 [(ethereum.eth.ext.cast_type) = "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives.Slot"];
}
message LightClientOptimisticUpdateAltair {
LightClientHeaderAltair attested_header = 1;
SyncAggregate sync_aggregate = 2;
uint64 signature_slot = 3 [(ethereum.eth.ext.cast_type) = "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives.Slot"];
}
message LightClientOptimisticUpdateCapella {
LightClientHeaderCapella attested_header = 1;
SyncAggregate sync_aggregate = 2;
uint64 signature_slot = 3 [(ethereum.eth.ext.cast_type) = "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives.Slot"];
}
message LightClientOptimisticUpdateDeneb {
LightClientHeaderDeneb attested_header = 1;
SyncAggregate sync_aggregate = 2;
uint64 signature_slot = 3 [(ethereum.eth.ext.cast_type) = "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives.Slot"];
}

View File

@@ -1,5 +1,5 @@
// Code generated by fastssz. DO NOT EDIT.
// Hash: 4cb7a5705004491db2ef29a5080a4cc56a1b618de948a86f9e5275858b48e6c4
// Hash: bfd7d6b556134c3bd236b880245717aa01ae79573b33f2746a08c165ba5dcedb
package eth
import (

View File

@@ -1,5 +1,5 @@
// Code generated by fastssz. DO NOT EDIT.
// Hash: 0afa289ce68dc2913d8000d495c6069832f35b66a6c0cf1bb0d1299fcad7047a
// Hash: 5797213d138ec1a089f9dae2198cab6f4f829ac0cc1f0bda2633fff544db4e68
package eth
import (
@@ -3979,7 +3979,10 @@ func (v *Validator) UnmarshalSSZ(buf []byte) error {
v.EffectiveBalance = ssz.UnmarshallUint64(buf[80:88])
// Field (3) 'Slashed'
v.Slashed = ssz.UnmarshalBool(buf[88:89])
v.Slashed, err = ssz.DecodeBool(buf[88:89])
if err != nil {
return err
}
// Field (4) 'ActivationEligibilityEpoch'
v.ActivationEligibilityEpoch = github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.Epoch(ssz.UnmarshallUint64(buf[89:97]))

View File

@@ -49,6 +49,7 @@ go_test(
"generate_genesis_state_bellatrix_test.go",
"generate_genesis_state_test.go",
"generate_keys_test.go",
"premine-state_test.go",
],
data = [
"keygen_test_vector.yaml",
@@ -61,9 +62,12 @@ go_test(
"//container/trie:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//runtime/version:go_default_library",
"//testing/assert:go_default_library",
"//testing/require:go_default_library",
"//time:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
"@com_github_ethereum_go_ethereum//core/types:go_default_library",
"@com_github_go_yaml_yaml//:go_default_library",
"@io_bazel_rules_go//go/tools/bazel:go_default_library",
],

View File

@@ -155,6 +155,11 @@ func (s *PremineGenesisConfig) empty() (state.BeaconState, error) {
if err != nil {
return nil, err
}
case version.Electra:
e, err = state_native.InitializeFromProtoElectra(&ethpb.BeaconStateElectra{})
if err != nil {
return nil, err
}
default:
return nil, errUnsupportedVersion
}
@@ -336,6 +341,8 @@ func (s *PremineGenesisConfig) setFork(g state.BeaconState) error {
pv, cv = params.BeaconConfig().BellatrixForkVersion, params.BeaconConfig().CapellaForkVersion
case version.Deneb:
pv, cv = params.BeaconConfig().CapellaForkVersion, params.BeaconConfig().DenebForkVersion
case version.Electra:
pv, cv = params.BeaconConfig().ElectraForkVersion, params.BeaconConfig().ElectraForkVersion
default:
return errUnsupportedVersion
}
@@ -524,6 +531,39 @@ func (s *PremineGenesisConfig) setLatestBlockHeader(g state.BeaconState) error {
BlsToExecutionChanges: make([]*ethpb.SignedBLSToExecutionChange, 0),
BlobKzgCommitments: make([][]byte, 0),
}
case version.Electra:
body = &ethpb.BeaconBlockBodyElectra{
RandaoReveal: make([]byte, 96),
Eth1Data: &ethpb.Eth1Data{
DepositRoot: make([]byte, 32),
BlockHash: make([]byte, 32),
},
Graffiti: make([]byte, 32),
SyncAggregate: &ethpb.SyncAggregate{
SyncCommitteeBits: make([]byte, fieldparams.SyncCommitteeLength/8),
SyncCommitteeSignature: make([]byte, fieldparams.BLSSignatureLength),
},
ExecutionPayload: &enginev1.ExecutionPayloadElectra{
ParentHash: make([]byte, 32),
FeeRecipient: make([]byte, 20),
StateRoot: make([]byte, 32),
ReceiptsRoot: make([]byte, 32),
LogsBloom: make([]byte, 256),
PrevRandao: make([]byte, 32),
ExtraData: make([]byte, 0),
BaseFeePerGas: make([]byte, 32),
BlockHash: make([]byte, 32),
Transactions: make([][]byte, 0),
Withdrawals: make([]*enginev1.Withdrawal, 0),
},
BlsToExecutionChanges: make([]*ethpb.SignedBLSToExecutionChange, 0),
BlobKzgCommitments: make([][]byte, 0),
ExecutionRequests: &enginev1.ExecutionRequests{
Deposits: make([]*enginev1.DepositRequest, 0),
Withdrawals: make([]*enginev1.WithdrawalRequest, 0),
Consolidations: make([]*enginev1.ConsolidationRequest, 0),
},
}
default:
return errUnsupportedVersion
}
@@ -640,6 +680,38 @@ func (s *PremineGenesisConfig) setExecutionPayload(g state.BeaconState) error {
if err != nil {
return err
}
case version.Electra:
payload := &enginev1.ExecutionPayloadElectra{
ParentHash: gb.ParentHash().Bytes(),
FeeRecipient: gb.Coinbase().Bytes(),
StateRoot: gb.Root().Bytes(),
ReceiptsRoot: gb.ReceiptHash().Bytes(),
LogsBloom: gb.Bloom().Bytes(),
PrevRandao: params.BeaconConfig().ZeroHash[:],
BlockNumber: gb.NumberU64(),
GasLimit: gb.GasLimit(),
GasUsed: gb.GasUsed(),
Timestamp: gb.Time(),
ExtraData: gb.Extra()[:32],
BaseFeePerGas: bytesutil.PadTo(bytesutil.ReverseByteOrder(gb.BaseFee().Bytes()), fieldparams.RootLength),
BlockHash: gb.Hash().Bytes(),
Transactions: make([][]byte, 0),
Withdrawals: make([]*enginev1.Withdrawal, 0),
ExcessBlobGas: *gb.ExcessBlobGas(),
BlobGasUsed: *gb.BlobGasUsed(),
}
wep, err := blocks.WrappedExecutionPayloadElectra(payload)
if err != nil {
return err
}
eph, err := blocks.PayloadToHeaderElectra(wep)
if err != nil {
return err
}
ed, err = blocks.WrappedExecutionPayloadHeaderElectra(eph)
if err != nil {
return err
}
default:
return errUnsupportedVersion
}

View File

@@ -0,0 +1,26 @@
package interop
import (
"context"
"math/big"
"testing"
"github.com/ethereum/go-ethereum/core/types"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/prysmaticlabs/prysm/v5/testing/require"
"github.com/prysmaticlabs/prysm/v5/time"
)
func TestPremineGenesis_Electra(t *testing.T) {
one := uint64(1)
genesis := types.NewBlockWithHeader(&types.Header{
Time: uint64(time.Now().Unix()),
Extra: make([]byte, 32),
BaseFee: big.NewInt(1),
ExcessBlobGas: &one,
BlobGasUsed: &one,
})
_, err := NewPreminedGenesis(context.Background(), genesis.Time(), 10, 10, version.Electra, genesis)
require.NoError(t, err)
}

View File

@@ -43,6 +43,7 @@ go_library(
"//beacon-chain/state/stateutil:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//consensus-types:go_default_library",
"//consensus-types/blocks:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//consensus-types/primitives:go_default_library",
@@ -51,6 +52,7 @@ go_library(
"//crypto/hash:go_default_library",
"//crypto/rand:go_default_library",
"//encoding/bytesutil:go_default_library",
"//encoding/ssz:go_default_library",
"//network/forks:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/eth/v1:go_default_library",

View File

@@ -4,14 +4,20 @@ import (
"context"
"testing"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/config/params"
consensus_types "github.com/prysmaticlabs/prysm/v5/consensus-types"
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/encoding/ssz"
v11 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
ethpbv1 "github.com/prysmaticlabs/prysm/v5/proto/eth/v1"
ethpbv2 "github.com/prysmaticlabs/prysm/v5/proto/eth/v2"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/prysmaticlabs/prysm/v5/testing/require"
)
@@ -21,7 +27,7 @@ type TestLightClient struct {
State state.BeaconState
Block interfaces.ReadOnlySignedBeaconBlock
AttestedState state.BeaconState
AttestedHeader *ethpb.BeaconBlockHeader
AttestedBlock interfaces.ReadOnlySignedBeaconBlock
FinalizedBlock interfaces.ReadOnlySignedBeaconBlock
}
@@ -39,6 +45,19 @@ func (l *TestLightClient) SetupTestCapella(blinded bool) *TestLightClient {
err = attestedState.SetSlot(slot)
require.NoError(l.T, err)
finalizedBlock, err := blocks.NewSignedBeaconBlock(NewBeaconBlockCapella())
require.NoError(l.T, err)
finalizedBlock.SetSlot(1)
finalizedHeader, err := finalizedBlock.Header()
require.NoError(l.T, err)
finalizedRoot, err := finalizedHeader.Header.HashTreeRoot()
require.NoError(l.T, err)
require.NoError(l.T, attestedState.SetFinalizedCheckpoint(&ethpb.Checkpoint{
Epoch: params.BeaconConfig().CapellaForkEpoch - 10,
Root: finalizedRoot[:],
}))
parent := NewBeaconBlockCapella()
parent.Block.Slot = slot
@@ -120,9 +139,122 @@ func (l *TestLightClient) SetupTestCapella(blinded bool) *TestLightClient {
l.State = state
l.AttestedState = attestedState
l.AttestedHeader = attestedHeader
l.AttestedBlock = signedParent
l.Block = signedBlock
l.Ctx = ctx
l.FinalizedBlock = finalizedBlock
return l
}
func (l *TestLightClient) SetupTestCapellaFinalizedBlockAltair(blinded bool) *TestLightClient {
ctx := context.Background()
slot := primitives.Slot(params.BeaconConfig().CapellaForkEpoch * primitives.Epoch(params.BeaconConfig().SlotsPerEpoch)).Add(1)
attestedState, err := NewBeaconStateCapella()
require.NoError(l.T, err)
err = attestedState.SetSlot(slot)
require.NoError(l.T, err)
finalizedBlock, err := blocks.NewSignedBeaconBlock(NewBeaconBlockAltair())
require.NoError(l.T, err)
finalizedBlock.SetSlot(1)
finalizedHeader, err := finalizedBlock.Header()
require.NoError(l.T, err)
finalizedRoot, err := finalizedHeader.Header.HashTreeRoot()
require.NoError(l.T, err)
require.NoError(l.T, attestedState.SetFinalizedCheckpoint(&ethpb.Checkpoint{
Epoch: params.BeaconConfig().AltairForkEpoch - 10,
Root: finalizedRoot[:],
}))
parent := NewBeaconBlockCapella()
parent.Block.Slot = slot
signedParent, err := blocks.NewSignedBeaconBlock(parent)
require.NoError(l.T, err)
parentHeader, err := signedParent.Header()
require.NoError(l.T, err)
attestedHeader := parentHeader.Header
err = attestedState.SetLatestBlockHeader(attestedHeader)
require.NoError(l.T, err)
attestedStateRoot, err := attestedState.HashTreeRoot(ctx)
require.NoError(l.T, err)
// get a new signed block so the root is updated with the new state root
parent.Block.StateRoot = attestedStateRoot[:]
signedParent, err = blocks.NewSignedBeaconBlock(parent)
require.NoError(l.T, err)
state, err := NewBeaconStateCapella()
require.NoError(l.T, err)
err = state.SetSlot(slot)
require.NoError(l.T, err)
parentRoot, err := signedParent.Block().HashTreeRoot()
require.NoError(l.T, err)
var signedBlock interfaces.SignedBeaconBlock
if blinded {
block := NewBlindedBeaconBlockCapella()
block.Block.Slot = slot
block.Block.ParentRoot = parentRoot[:]
for i := uint64(0); i < params.BeaconConfig().MinSyncCommitteeParticipants; i++ {
block.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true)
}
signedBlock, err = blocks.NewSignedBeaconBlock(block)
require.NoError(l.T, err)
h, err := signedBlock.Header()
require.NoError(l.T, err)
err = state.SetLatestBlockHeader(h.Header)
require.NoError(l.T, err)
stateRoot, err := state.HashTreeRoot(ctx)
require.NoError(l.T, err)
// get a new signed block so the root is updated with the new state root
block.Block.StateRoot = stateRoot[:]
signedBlock, err = blocks.NewSignedBeaconBlock(block)
require.NoError(l.T, err)
} else {
block := NewBeaconBlockCapella()
block.Block.Slot = slot
block.Block.ParentRoot = parentRoot[:]
for i := uint64(0); i < params.BeaconConfig().MinSyncCommitteeParticipants; i++ {
block.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true)
}
signedBlock, err = blocks.NewSignedBeaconBlock(block)
require.NoError(l.T, err)
h, err := signedBlock.Header()
require.NoError(l.T, err)
err = state.SetLatestBlockHeader(h.Header)
require.NoError(l.T, err)
stateRoot, err := state.HashTreeRoot(ctx)
require.NoError(l.T, err)
// get a new signed block so the root is updated with the new state root
block.Block.StateRoot = stateRoot[:]
signedBlock, err = blocks.NewSignedBeaconBlock(block)
require.NoError(l.T, err)
}
l.State = state
l.AttestedState = attestedState
l.AttestedBlock = signedParent
l.Block = signedBlock
l.Ctx = ctx
l.FinalizedBlock = finalizedBlock
return l
}
@@ -137,6 +269,19 @@ func (l *TestLightClient) SetupTestAltair() *TestLightClient {
err = attestedState.SetSlot(slot)
require.NoError(l.T, err)
finalizedBlock, err := blocks.NewSignedBeaconBlock(NewBeaconBlockAltair())
require.NoError(l.T, err)
finalizedBlock.SetSlot(1)
finalizedHeader, err := finalizedBlock.Header()
require.NoError(l.T, err)
finalizedRoot, err := finalizedHeader.Header.HashTreeRoot()
require.NoError(l.T, err)
require.NoError(l.T, attestedState.SetFinalizedCheckpoint(&ethpb.Checkpoint{
Epoch: params.BeaconConfig().AltairForkEpoch - 10,
Root: finalizedRoot[:],
}))
parent := NewBeaconBlockAltair()
parent.Block.Slot = slot
@@ -191,9 +336,10 @@ func (l *TestLightClient) SetupTestAltair() *TestLightClient {
l.State = state
l.AttestedState = attestedState
l.AttestedHeader = attestedHeader
l.Block = signedBlock
l.Ctx = ctx
l.FinalizedBlock = finalizedBlock
l.AttestedBlock = signedParent
return l
}
@@ -208,6 +354,19 @@ func (l *TestLightClient) SetupTestDeneb(blinded bool) *TestLightClient {
err = attestedState.SetSlot(slot)
require.NoError(l.T, err)
finalizedBlock, err := blocks.NewSignedBeaconBlock(NewBeaconBlockDeneb())
require.NoError(l.T, err)
finalizedBlock.SetSlot(1)
finalizedHeader, err := finalizedBlock.Header()
require.NoError(l.T, err)
finalizedRoot, err := finalizedHeader.Header.HashTreeRoot()
require.NoError(l.T, err)
require.NoError(l.T, attestedState.SetFinalizedCheckpoint(&ethpb.Checkpoint{
Epoch: params.BeaconConfig().DenebForkEpoch - 10,
Root: finalizedRoot[:],
}))
parent := NewBeaconBlockDeneb()
parent.Block.Slot = slot
@@ -289,9 +448,234 @@ func (l *TestLightClient) SetupTestDeneb(blinded bool) *TestLightClient {
l.State = state
l.AttestedState = attestedState
l.AttestedHeader = attestedHeader
l.AttestedBlock = signedParent
l.Block = signedBlock
l.Ctx = ctx
l.FinalizedBlock = finalizedBlock
return l
}
func (l *TestLightClient) SetupTestElectra(blinded bool) *TestLightClient {
ctx := context.Background()
slot := primitives.Slot(params.BeaconConfig().ElectraForkEpoch * primitives.Epoch(params.BeaconConfig().SlotsPerEpoch)).Add(1)
attestedState, err := NewBeaconStateElectra()
require.NoError(l.T, err)
err = attestedState.SetSlot(slot)
require.NoError(l.T, err)
finalizedBlock, err := blocks.NewSignedBeaconBlock(NewBeaconBlockElectra())
require.NoError(l.T, err)
finalizedBlock.SetSlot(1)
finalizedHeader, err := finalizedBlock.Header()
require.NoError(l.T, err)
finalizedRoot, err := finalizedHeader.Header.HashTreeRoot()
require.NoError(l.T, err)
require.NoError(l.T, attestedState.SetFinalizedCheckpoint(&ethpb.Checkpoint{
Epoch: params.BeaconConfig().ElectraForkEpoch - 10,
Root: finalizedRoot[:],
}))
parent := NewBeaconBlockElectra()
parent.Block.Slot = slot
signedParent, err := blocks.NewSignedBeaconBlock(parent)
require.NoError(l.T, err)
parentHeader, err := signedParent.Header()
require.NoError(l.T, err)
attestedHeader := parentHeader.Header
err = attestedState.SetLatestBlockHeader(attestedHeader)
require.NoError(l.T, err)
attestedStateRoot, err := attestedState.HashTreeRoot(ctx)
require.NoError(l.T, err)
// get a new signed block so the root is updated with the new state root
parent.Block.StateRoot = attestedStateRoot[:]
signedParent, err = blocks.NewSignedBeaconBlock(parent)
require.NoError(l.T, err)
state, err := NewBeaconStateElectra()
require.NoError(l.T, err)
err = state.SetSlot(slot)
require.NoError(l.T, err)
parentRoot, err := signedParent.Block().HashTreeRoot()
require.NoError(l.T, err)
var signedBlock interfaces.SignedBeaconBlock
if blinded {
block := NewBlindedBeaconBlockElectra()
block.Message.Slot = slot
block.Message.ParentRoot = parentRoot[:]
for i := uint64(0); i < params.BeaconConfig().MinSyncCommitteeParticipants; i++ {
block.Message.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true)
}
signedBlock, err = blocks.NewSignedBeaconBlock(block)
require.NoError(l.T, err)
h, err := signedBlock.Header()
require.NoError(l.T, err)
err = state.SetLatestBlockHeader(h.Header)
require.NoError(l.T, err)
stateRoot, err := state.HashTreeRoot(ctx)
require.NoError(l.T, err)
// get a new signed block so the root is updated with the new state root
block.Message.StateRoot = stateRoot[:]
signedBlock, err = blocks.NewSignedBeaconBlock(block)
require.NoError(l.T, err)
} else {
block := NewBeaconBlockElectra()
block.Block.Slot = slot
block.Block.ParentRoot = parentRoot[:]
for i := uint64(0); i < params.BeaconConfig().MinSyncCommitteeParticipants; i++ {
block.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true)
}
signedBlock, err = blocks.NewSignedBeaconBlock(block)
require.NoError(l.T, err)
h, err := signedBlock.Header()
require.NoError(l.T, err)
err = state.SetLatestBlockHeader(h.Header)
require.NoError(l.T, err)
stateRoot, err := state.HashTreeRoot(ctx)
require.NoError(l.T, err)
// get a new signed block so the root is updated with the new state root
block.Block.StateRoot = stateRoot[:]
signedBlock, err = blocks.NewSignedBeaconBlock(block)
require.NoError(l.T, err)
}
l.State = state
l.AttestedState = attestedState
l.AttestedBlock = signedParent
l.Block = signedBlock
l.Ctx = ctx
l.FinalizedBlock = finalizedBlock
return l
}
func (l *TestLightClient) SetupTestDenebFinalizedBlockCapella(blinded bool) *TestLightClient {
ctx := context.Background()
slot := primitives.Slot(params.BeaconConfig().DenebForkEpoch * primitives.Epoch(params.BeaconConfig().SlotsPerEpoch)).Add(1)
attestedState, err := NewBeaconStateDeneb()
require.NoError(l.T, err)
err = attestedState.SetSlot(slot)
require.NoError(l.T, err)
finalizedBlock, err := blocks.NewSignedBeaconBlock(NewBeaconBlockCapella())
require.NoError(l.T, err)
finalizedBlock.SetSlot(1)
finalizedHeader, err := finalizedBlock.Header()
require.NoError(l.T, err)
finalizedRoot, err := finalizedHeader.Header.HashTreeRoot()
require.NoError(l.T, err)
require.NoError(l.T, attestedState.SetFinalizedCheckpoint(&ethpb.Checkpoint{
Epoch: params.BeaconConfig().CapellaForkEpoch - 10,
Root: finalizedRoot[:],
}))
parent := NewBeaconBlockDeneb()
parent.Block.Slot = slot
signedParent, err := blocks.NewSignedBeaconBlock(parent)
require.NoError(l.T, err)
parentHeader, err := signedParent.Header()
require.NoError(l.T, err)
attestedHeader := parentHeader.Header
err = attestedState.SetLatestBlockHeader(attestedHeader)
require.NoError(l.T, err)
attestedStateRoot, err := attestedState.HashTreeRoot(ctx)
require.NoError(l.T, err)
// get a new signed block so the root is updated with the new state root
parent.Block.StateRoot = attestedStateRoot[:]
signedParent, err = blocks.NewSignedBeaconBlock(parent)
require.NoError(l.T, err)
state, err := NewBeaconStateDeneb()
require.NoError(l.T, err)
err = state.SetSlot(slot)
require.NoError(l.T, err)
parentRoot, err := signedParent.Block().HashTreeRoot()
require.NoError(l.T, err)
var signedBlock interfaces.SignedBeaconBlock
if blinded {
block := NewBlindedBeaconBlockDeneb()
block.Message.Slot = slot
block.Message.ParentRoot = parentRoot[:]
for i := uint64(0); i < params.BeaconConfig().MinSyncCommitteeParticipants; i++ {
block.Message.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true)
}
signedBlock, err = blocks.NewSignedBeaconBlock(block)
require.NoError(l.T, err)
h, err := signedBlock.Header()
require.NoError(l.T, err)
err = state.SetLatestBlockHeader(h.Header)
require.NoError(l.T, err)
stateRoot, err := state.HashTreeRoot(ctx)
require.NoError(l.T, err)
// get a new signed block so the root is updated with the new state root
block.Message.StateRoot = stateRoot[:]
signedBlock, err = blocks.NewSignedBeaconBlock(block)
require.NoError(l.T, err)
} else {
block := NewBeaconBlockDeneb()
block.Block.Slot = slot
block.Block.ParentRoot = parentRoot[:]
for i := uint64(0); i < params.BeaconConfig().MinSyncCommitteeParticipants; i++ {
block.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true)
}
signedBlock, err = blocks.NewSignedBeaconBlock(block)
require.NoError(l.T, err)
h, err := signedBlock.Header()
require.NoError(l.T, err)
err = state.SetLatestBlockHeader(h.Header)
require.NoError(l.T, err)
stateRoot, err := state.HashTreeRoot(ctx)
require.NoError(l.T, err)
// get a new signed block so the root is updated with the new state root
block.Block.StateRoot = stateRoot[:]
signedBlock, err = blocks.NewSignedBeaconBlock(block)
require.NoError(l.T, err)
}
l.State = state
l.AttestedState = attestedState
l.AttestedBlock = signedParent
l.Block = signedBlock
l.Ctx = ctx
l.FinalizedBlock = finalizedBlock
return l
}
@@ -299,14 +683,124 @@ func (l *TestLightClient) SetupTestDeneb(blinded bool) *TestLightClient {
func (l *TestLightClient) CheckAttestedHeader(container *ethpbv2.LightClientHeaderContainer) {
updateAttestedHeaderBeacon, err := container.GetBeacon()
require.NoError(l.T, err)
require.Equal(l.T, l.AttestedHeader.Slot, updateAttestedHeaderBeacon.Slot, "Attested header slot is not equal")
require.Equal(l.T, l.AttestedHeader.ProposerIndex, updateAttestedHeaderBeacon.ProposerIndex, "Attested header proposer index is not equal")
require.DeepSSZEqual(l.T, l.AttestedHeader.ParentRoot, updateAttestedHeaderBeacon.ParentRoot, "Attested header parent root is not equal")
require.DeepSSZEqual(l.T, l.AttestedHeader.BodyRoot, updateAttestedHeaderBeacon.BodyRoot, "Attested header body root is not equal")
testAttestedHeader, err := l.AttestedBlock.Header()
require.NoError(l.T, err)
require.Equal(l.T, l.AttestedBlock.Block().Slot(), updateAttestedHeaderBeacon.Slot, "Attested block slot is not equal")
require.Equal(l.T, testAttestedHeader.Header.ProposerIndex, updateAttestedHeaderBeacon.ProposerIndex, "Attested block proposer index is not equal")
require.DeepSSZEqual(l.T, testAttestedHeader.Header.ParentRoot, updateAttestedHeaderBeacon.ParentRoot, "Attested block parent root is not equal")
require.DeepSSZEqual(l.T, testAttestedHeader.Header.BodyRoot, updateAttestedHeaderBeacon.BodyRoot, "Attested block body root is not equal")
attestedStateRoot, err := l.AttestedState.HashTreeRoot(l.Ctx)
require.NoError(l.T, err)
require.DeepSSZEqual(l.T, attestedStateRoot[:], updateAttestedHeaderBeacon.StateRoot, "Attested header state root is not equal")
require.DeepSSZEqual(l.T, attestedStateRoot[:], updateAttestedHeaderBeacon.StateRoot, "Attested block state root is not equal")
if l.AttestedBlock.Version() == version.Capella {
payloadInterface, err := l.AttestedBlock.Block().Body().Execution()
require.NoError(l.T, err)
transactionsRoot, err := payloadInterface.TransactionsRoot()
if errors.Is(err, consensus_types.ErrUnsupportedField) {
transactions, err := payloadInterface.Transactions()
require.NoError(l.T, err)
transactionsRootArray, err := ssz.TransactionsRoot(transactions)
require.NoError(l.T, err)
transactionsRoot = transactionsRootArray[:]
} else {
require.NoError(l.T, err)
}
withdrawalsRoot, err := payloadInterface.WithdrawalsRoot()
if errors.Is(err, consensus_types.ErrUnsupportedField) {
withdrawals, err := payloadInterface.Withdrawals()
require.NoError(l.T, err)
withdrawalsRootArray, err := ssz.WithdrawalSliceRoot(withdrawals, fieldparams.MaxWithdrawalsPerPayload)
require.NoError(l.T, err)
withdrawalsRoot = withdrawalsRootArray[:]
} else {
require.NoError(l.T, err)
}
execution := &v11.ExecutionPayloadHeaderCapella{
ParentHash: payloadInterface.ParentHash(),
FeeRecipient: payloadInterface.FeeRecipient(),
StateRoot: payloadInterface.StateRoot(),
ReceiptsRoot: payloadInterface.ReceiptsRoot(),
LogsBloom: payloadInterface.LogsBloom(),
PrevRandao: payloadInterface.PrevRandao(),
BlockNumber: payloadInterface.BlockNumber(),
GasLimit: payloadInterface.GasLimit(),
GasUsed: payloadInterface.GasUsed(),
Timestamp: payloadInterface.Timestamp(),
ExtraData: payloadInterface.ExtraData(),
BaseFeePerGas: payloadInterface.BaseFeePerGas(),
BlockHash: payloadInterface.BlockHash(),
TransactionsRoot: transactionsRoot,
WithdrawalsRoot: withdrawalsRoot,
}
updateAttestedHeaderExecution, err := container.GetExecutionHeaderCapella()
require.NoError(l.T, err)
require.DeepSSZEqual(l.T, execution, updateAttestedHeaderExecution, "Attested Block Execution is not equal")
executionPayloadProof, err := blocks.PayloadProof(l.Ctx, l.AttestedBlock.Block())
require.NoError(l.T, err)
updateAttestedHeaderExecutionBranch, err := container.GetExecutionBranch()
require.NoError(l.T, err)
for i, leaf := range updateAttestedHeaderExecutionBranch {
require.DeepSSZEqual(l.T, executionPayloadProof[i], leaf, "Leaf is not equal")
}
}
if l.AttestedBlock.Version() == version.Deneb {
payloadInterface, err := l.AttestedBlock.Block().Body().Execution()
require.NoError(l.T, err)
transactionsRoot, err := payloadInterface.TransactionsRoot()
if errors.Is(err, consensus_types.ErrUnsupportedField) {
transactions, err := payloadInterface.Transactions()
require.NoError(l.T, err)
transactionsRootArray, err := ssz.TransactionsRoot(transactions)
require.NoError(l.T, err)
transactionsRoot = transactionsRootArray[:]
} else {
require.NoError(l.T, err)
}
withdrawalsRoot, err := payloadInterface.WithdrawalsRoot()
if errors.Is(err, consensus_types.ErrUnsupportedField) {
withdrawals, err := payloadInterface.Withdrawals()
require.NoError(l.T, err)
withdrawalsRootArray, err := ssz.WithdrawalSliceRoot(withdrawals, fieldparams.MaxWithdrawalsPerPayload)
require.NoError(l.T, err)
withdrawalsRoot = withdrawalsRootArray[:]
} else {
require.NoError(l.T, err)
}
execution := &v11.ExecutionPayloadHeaderDeneb{
ParentHash: payloadInterface.ParentHash(),
FeeRecipient: payloadInterface.FeeRecipient(),
StateRoot: payloadInterface.StateRoot(),
ReceiptsRoot: payloadInterface.ReceiptsRoot(),
LogsBloom: payloadInterface.LogsBloom(),
PrevRandao: payloadInterface.PrevRandao(),
BlockNumber: payloadInterface.BlockNumber(),
GasLimit: payloadInterface.GasLimit(),
GasUsed: payloadInterface.GasUsed(),
Timestamp: payloadInterface.Timestamp(),
ExtraData: payloadInterface.ExtraData(),
BaseFeePerGas: payloadInterface.BaseFeePerGas(),
BlockHash: payloadInterface.BlockHash(),
TransactionsRoot: transactionsRoot,
WithdrawalsRoot: withdrawalsRoot,
}
updateAttestedHeaderExecution, err := container.GetExecutionHeaderDeneb()
require.NoError(l.T, err)
require.DeepSSZEqual(l.T, execution, updateAttestedHeaderExecution, "Attested Block Execution is not equal")
executionPayloadProof, err := blocks.PayloadProof(l.Ctx, l.AttestedBlock.Block())
require.NoError(l.T, err)
updateAttestedHeaderExecutionBranch, err := container.GetExecutionBranch()
require.NoError(l.T, err)
for i, leaf := range updateAttestedHeaderExecutionBranch {
require.DeepSSZEqual(l.T, executionPayloadProof[i], leaf, "Leaf is not equal")
}
}
}
func (l *TestLightClient) CheckSyncAggregate(sa *ethpbv1.SyncAggregate) {

View File

@@ -1262,13 +1262,16 @@ func (v *validator) updateValidatorStatusCache(ctx context.Context, pubkeys [][f
if len(resp.Statuses) != len(resp.Indices) {
return fmt.Errorf("expected %d indices in status, received %d", len(resp.Statuses), len(resp.Indices))
}
pubkeyToStatus := make(map[[fieldparams.BLSPubkeyLength]byte]*validatorStatus, len(resp.Statuses))
for i, s := range resp.Statuses {
v.pubkeyToStatus[bytesutil.ToBytes48(resp.PublicKeys[i])] = &validatorStatus{
pubkeyToStatus[bytesutil.ToBytes48(resp.PublicKeys[i])] = &validatorStatus{
publicKey: resp.PublicKeys[i],
status: s,
index: resp.Indices[i],
}
}
v.pubkeyToStatus = pubkeyToStatus
return nil
}

View File

@@ -2908,3 +2908,63 @@ func TestValidator_ChangeHost(t *testing.T) {
v.ChangeHost()
assert.Equal(t, uint64(0), v.currentHostIndex)
}
func TestUpdateValidatorStatusCache(t *testing.T) {
ctx := context.Background()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
pubkeys := [][fieldparams.BLSPubkeyLength]byte{
{0x01},
{0x02},
}
statusRequestKeys := [][]byte{
pubkeys[0][:],
pubkeys[1][:],
}
client := validatormock.NewMockValidatorClient(ctrl)
mockResponse := &ethpb.MultipleValidatorStatusResponse{
PublicKeys: statusRequestKeys,
Statuses: []*ethpb.ValidatorStatusResponse{
{
Status: ethpb.ValidatorStatus_ACTIVE,
}, {
Status: ethpb.ValidatorStatus_EXITING,
}},
Indices: []primitives.ValidatorIndex{1, 2},
}
client.EXPECT().MultipleValidatorStatus(
gomock.Any(),
gomock.Any()).Return(mockResponse, nil)
v := &validator{
validatorClient: client,
beaconNodeHosts: []string{"http://localhost:8080", "http://localhost:8081"},
currentHostIndex: 0,
pubkeyToStatus: map[[fieldparams.BLSPubkeyLength]byte]*validatorStatus{
[fieldparams.BLSPubkeyLength]byte{0x03}: &validatorStatus{ // add non existant key and status to cache, should be fully removed on update
publicKey: []byte{0x03},
status: &ethpb.ValidatorStatusResponse{
Status: ethpb.ValidatorStatus_ACTIVE,
},
index: 3,
},
},
}
err := v.updateValidatorStatusCache(ctx, pubkeys)
assert.NoError(t, err)
// make sure the nonexistant key is fully removed
_, ok := v.pubkeyToStatus[[fieldparams.BLSPubkeyLength]byte{0x03}]
require.Equal(t, false, ok)
// make sure we only have the added values
assert.Equal(t, 2, len(v.pubkeyToStatus))
for i, pk := range pubkeys {
status, exists := v.pubkeyToStatus[pk]
require.Equal(t, true, exists)
require.DeepEqual(t, pk[:], status.publicKey)
require.Equal(t, mockResponse.Statuses[i], status.status)
require.Equal(t, mockResponse.Indices[i], status.index)
}
}