Compare commits

..

9 Commits

Author SHA1 Message Date
Taranpreet26311
1ddf3283dc Merge branch 'develop' into Horusec_Fix 2024-09-10 16:24:33 +04:00
Taranpreet26311
f62528a46f Merge branch 'develop' into Horusec_Fix 2024-09-05 20:50:29 +04:00
Taranpreet26311
6df4dd6cae Merge branch 'develop' into Horusec_Fix 2024-09-04 13:43:13 +04:00
Taranpreet26311
24352e19a6 Merge branch 'develop' into Horusec_Fix 2024-09-03 16:14:25 +04:00
Taranpreet26311
1a52554c59 Revert testing changes 2024-08-30 16:01:24 +04:00
Taranpreet26311
7d5f32d3b3 Make changes to test it on draft 2024-08-30 15:58:56 +04:00
Taranpreet26311
0dba9e99bf Added Horusec change 2024-08-30 15:47:24 +04:00
Taranpreet26311
124a843fa8 Add changes to test out Horusec 2024-08-30 15:36:51 +04:00
Taranpreet26311
4d17096f68 PR to fix Horusec scanner 2024-08-30 15:28:05 +04:00
360 changed files with 10976 additions and 10783 deletions

View File

@@ -12,11 +12,11 @@ jobs:
if: github.ref == 'refs/heads/develop'
steps:
- name: Check out code
uses: actions/checkout@v2
uses: actions/checkout@v4
with: # Required when commit authors is enabled
fetch-depth: 0
- name: Running Security Scan
run: |
curl -fsSL https://raw.githubusercontent.com/ZupIT/horusec/main/deployments/scripts/install.sh | bash -s latest
horusec start -t="10000" -p="./" -e="true" -i="**/crypto/bls/herumi/**, **/**/*_test.go, **/third_party/afl/**, **/crypto/keystore/key.go"
horusec start -D -t="10000" -p="./" -e="true" -i="**/crypto/bls/herumi/**, **/**/*_test.go, **/third_party/afl/**, **/crypto/keystore/key.go"

View File

@@ -26,6 +26,7 @@ approval_rules:
only_changed_files:
paths:
- "*pb.go"
- "*pb.gw.go"
- "*.bazel"
options:
ignore_commits_by:
@@ -68,6 +69,7 @@ approval_rules:
changed_files:
ignore:
- "*pb.go"
- "*pb.gw.go"
- "*.bazel"
options:
ignore_commits_by:

View File

@@ -13,19 +13,9 @@ 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 `BlockToLightClientHeader` function.
- Electra EIP6110: Queue deposit
- Light client support: Implement `BlockToLightClientHeaderXXX` functions upto Deneb
- 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.
- 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.
@@ -40,27 +30,14 @@ The format is based on Keep a Changelog, and this project adheres to Semantic Ve
- `grpc-gateway-corsdomain` is renamed to http-cors-domain. The old name can still be used as an alias.
- `api-timeout` is changed from int flag to duration flag, default value updated.
- Light client support: abstracted out the light client headers with different versions.
- Electra EIP6110: Queue deposit requests changes from consensus spec pr #3818
- `ApplyToEveryValidator` has been changed to prevent misuse bugs, it takes a closure that takes a `ReadOnlyValidator` and returns a raw pointer to a `Validator`.
- Removed gorilla mux library and replaced it with net/http updates in go 1.22.
- Clean up `ProposeBlock` for validator client to reduce cognitive scoring and enable further changes.
- 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.
- Switch to compounding when consolidating with source==target.
### Deprecated
- `--disable-grpc-gateway` flag is deprecated due to grpc gateway removal.
- `--enable-experimental-state` flag is deprecated. This feature is now on by default. Opt-out with `--disable-experimental-state`.
### Removed
- removed gRPC Gateway
- Removed unused blobs bundle cache
- Removed consolidation signing domain from params. The Electra design changed such that EL handles consolidation signature verification.
### Fixed
@@ -72,13 +49,7 @@ The format is based on Keep a Changelog, and this project adheres to Semantic Ve
- validator registration log changed to debug, and the frequency of validator registration calls are reduced
- Core: Fix process effective balance update to safe copy validator for Electra.
- `== nil` checks before calling `IsNil()` on interfaces to prevent panics.
- 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.
- Core: Fixed slash processing causing extra hashing
### Security
@@ -2691,7 +2662,7 @@ on your validators.
**Beacon chain node**
| Metric | Description | References |
| ------------------------------------------------ | ----------------------------------------------------------------------------------------------------- | ---------- |
|--------------------------------------------------|-------------------------------------------------------------------------------------------------------|------------|
| `p2p_message_ignored_validation_total` | Count of messages that were ignored in validation | |
| `beacon_current_active_validators` | Current total active validators | |
| `beacon_processed_deposits_total` | Total number of deposits processed | |
@@ -2742,9 +2713,9 @@ on your validators.
#### Changed Metrics
**Beacon chain node**
| Metric | Old Name | Description | References |
| --------------------- | -------------------- | ---------------------------------------------------- | ---------- |
| `beacon_reorgs_total` | `beacon_reorg_total` | Count the number of times a beacon chain has a reorg | |
| Metric | Old Name | Description | References |
|-----------------------|----------------------|------------------------------------------------------|------------|
| `beacon_reorgs_total` | `beacon_reorg_total` | Count the number of times a beacon chain has a reorg | |
### Deprecated

View File

@@ -227,7 +227,7 @@ filegroup(
url = "https://github.com/ethereum/EIPs/archive/5480440fe51742ed23342b68cf106cefd427e39d.tar.gz",
)
consensus_spec_version = "v1.5.0-alpha.7"
consensus_spec_version = "v1.5.0-alpha.5"
bls_test_version = "v0.1.1"
@@ -243,7 +243,7 @@ filegroup(
visibility = ["//visibility:public"],
)
""",
integrity = "sha256-Vo4+1bsRNYMGXjlpIYKEqt2WPjeGSbjeFQFKVUhf1Yc=",
integrity = "sha256-R9vG5HEL5eGMOAmbkKfJ2jfelNqL5V0xBUPiXOiGM6U=",
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/general.tar.gz" % consensus_spec_version,
)
@@ -259,7 +259,7 @@ filegroup(
visibility = ["//visibility:public"],
)
""",
integrity = "sha256-TsQtQVPyQA6htrTjL1cd/oWEkM83aK4Y0pT9W6ssKYU=",
integrity = "sha256-AEIiEOlf1XuxoRMCsN+kgJMo4LrS05+biTA1p/7Ro00=",
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/minimal.tar.gz" % consensus_spec_version,
)
@@ -275,7 +275,7 @@ filegroup(
visibility = ["//visibility:public"],
)
""",
integrity = "sha256-4g7EijlsIJVKGADlVL6ka9ikcwow8WuKHaABONA0Cxg=",
integrity = "sha256-LH/Xr20yrJRYnbpjRGupMWTIOWt3cpxZJWXgThwVDsk=",
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/mainnet.tar.gz" % consensus_spec_version,
)
@@ -290,7 +290,7 @@ filegroup(
visibility = ["//visibility:public"],
)
""",
integrity = "sha256-i5+48P/BqxA+q39OufAiotW2llUq97+4j1++ViI96dM=",
integrity = "sha256-mlytz4MPjKh0DwV7FMiAtnRbJw9B6o78/x66/vmnYc8=",
strip_prefix = "consensus-specs-" + consensus_spec_version[1:],
url = "https://github.com/ethereum/consensus-specs/archive/refs/tags/%s.tar.gz" % consensus_spec_version,
)
@@ -342,22 +342,6 @@ 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

@@ -146,7 +146,7 @@ func (c *Client) do(ctx context.Context, method string, path string, body io.Rea
u := c.baseURL.ResolveReference(&url.URL{Path: path})
span.SetAttributes(trace.StringAttribute("url", u.String()),
span.AddAttributes(trace.StringAttribute("url", u.String()),
trace.StringAttribute("method", method))
req, err := http.NewRequestWithContext(ctx, method, u.String(), body)
@@ -259,7 +259,7 @@ func (c *Client) GetHeader(ctx context.Context, slot primitives.Slot, parentHash
func (c *Client) RegisterValidator(ctx context.Context, svr []*ethpb.SignedValidatorRegistrationV1) error {
ctx, span := trace.StartSpan(ctx, "builder.client.RegisterValidator")
defer span.End()
span.SetAttributes(trace.Int64Attribute("num_reqs", int64(len(svr))))
span.AddAttributes(trace.Int64Attribute("num_reqs", int64(len(svr))))
if len(svr) == 0 {
err := errors.Wrap(errMalformedRequest, "empty validator registration list")

View File

@@ -1,7 +1,5 @@
package api
import "net/http"
const (
VersionHeader = "Eth-Consensus-Version"
ExecutionPayloadBlindedHeader = "Eth-Execution-Payload-Blinded"
@@ -12,9 +10,3 @@ 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

@@ -10,8 +10,8 @@ go_library(
importpath = "github.com/prysmaticlabs/prysm/v5/api/server/httprest",
visibility = ["//visibility:public"],
deps = [
"//api/server/middleware:go_default_library",
"//runtime:go_default_library",
"@com_github_gorilla_mux//:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
],
@@ -25,6 +25,7 @@ go_test(
"//cmd/beacon-chain/flags:go_default_library",
"//testing/assert:go_default_library",
"//testing/require:go_default_library",
"@com_github_gorilla_mux//:go_default_library",
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
"@com_github_urfave_cli_v2//:go_default_library",
],

View File

@@ -3,22 +3,12 @@ package httprest
import (
"time"
"net/http"
"github.com/prysmaticlabs/prysm/v5/api/server/middleware"
"github.com/gorilla/mux"
)
// Option is a http rest server functional parameter type.
type Option func(g *Server) error
// WithMiddlewares sets the list of middlewares to be applied on routes.
func WithMiddlewares(mw []middleware.Middleware) Option {
return func(g *Server) error {
g.cfg.middlewares = mw
return nil
}
}
// WithHTTPAddr sets the full address ( host and port ) of the server.
func WithHTTPAddr(addr string) Option {
return func(g *Server) error {
@@ -28,7 +18,7 @@ func WithHTTPAddr(addr string) Option {
}
// WithRouter sets the internal router of the server, this is required.
func WithRouter(r *http.ServeMux) Option {
func WithRouter(r *mux.Router) Option {
return func(g *Server) error {
g.cfg.router = r
return nil

View File

@@ -5,8 +5,8 @@ import (
"net/http"
"time"
"github.com/gorilla/mux"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v5/api/server/middleware"
"github.com/prysmaticlabs/prysm/v5/runtime"
)
@@ -14,10 +14,9 @@ var _ runtime.Service = (*Server)(nil)
// Config parameters for setting up the http-rest service.
type config struct {
httpAddr string
middlewares []middleware.Middleware
router http.Handler
timeout time.Duration
httpAddr string
router *mux.Router
timeout time.Duration
}
// Server serves HTTP traffic.
@@ -45,10 +44,11 @@ func New(ctx context.Context, opts ...Option) (*Server, error) {
}
var handler http.Handler
defaultReadHeaderTimeout := time.Second
handler = middleware.MiddlewareChain(g.cfg.router, g.cfg.middlewares)
if g.cfg.timeout > 0*time.Second {
defaultReadHeaderTimeout = g.cfg.timeout
handler = http.TimeoutHandler(handler, g.cfg.timeout, "request timed out")
handler = http.TimeoutHandler(g.cfg.router, g.cfg.timeout, "request timed out")
} else {
handler = g.cfg.router
}
g.server = &http.Server{
Addr: g.cfg.httpAddr,

View File

@@ -4,12 +4,12 @@ import (
"context"
"flag"
"fmt"
"net"
"net/http"
"net/http/httptest"
"net/url"
"testing"
"github.com/gorilla/mux"
"github.com/prysmaticlabs/prysm/v5/cmd/beacon-chain/flags"
"github.com/prysmaticlabs/prysm/v5/testing/assert"
"github.com/prysmaticlabs/prysm/v5/testing/require"
@@ -25,13 +25,12 @@ func TestServer_StartStop(t *testing.T) {
ctx := cli.NewContext(&app, set, nil)
port := ctx.Int(flags.HTTPServerPort.Name)
portStr := fmt.Sprintf("%d", port) // Convert port to string
host := ctx.String(flags.HTTPServerHost.Name)
address := net.JoinHostPort(host, portStr)
handler := http.NewServeMux()
address := fmt.Sprintf("%s:%d", host, port)
opts := []Option{
WithHTTPAddr(address),
WithRouter(handler),
WithRouter(mux.NewRouter()),
}
g, err := New(context.Background(), opts...)
@@ -51,15 +50,13 @@ func TestServer_NilHandler_NotFoundHandlerRegistered(t *testing.T) {
set := flag.NewFlagSet("test", 0)
ctx := cli.NewContext(&app, set, nil)
handler := http.NewServeMux()
port := ctx.Int(flags.HTTPServerPort.Name)
portStr := fmt.Sprintf("%d", port) // Convert port to string
host := ctx.String(flags.HTTPServerHost.Name)
address := net.JoinHostPort(host, portStr)
address := fmt.Sprintf("%s:%d", host, port)
opts := []Option{
WithHTTPAddr(address),
WithRouter(handler),
WithRouter(mux.NewRouter()),
}
g, err := New(context.Background(), opts...)

View File

@@ -8,7 +8,10 @@ go_library(
],
importpath = "github.com/prysmaticlabs/prysm/v5/api/server/middleware",
visibility = ["//visibility:public"],
deps = ["@com_github_rs_cors//:go_default_library"],
deps = [
"@com_github_gorilla_mux//:go_default_library",
"@com_github_rs_cors//:go_default_library",
],
)
go_test(

View File

@@ -5,11 +5,10 @@ import (
"net/http"
"strings"
"github.com/gorilla/mux"
"github.com/rs/cors"
)
type Middleware func(http.Handler) http.Handler
// NormalizeQueryValuesHandler normalizes an input query of "key=value1,value2,value3" to "key=value1&key=value2&key=value3"
func NormalizeQueryValuesHandler(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@@ -22,7 +21,7 @@ func NormalizeQueryValuesHandler(next http.Handler) http.Handler {
}
// CorsHandler sets the cors settings on api endpoints
func CorsHandler(allowOrigins []string) Middleware {
func CorsHandler(allowOrigins []string) mux.MiddlewareFunc {
c := cors.New(cors.Options{
AllowedOrigins: allowOrigins,
AllowedMethods: []string{http.MethodPost, http.MethodGet, http.MethodDelete, http.MethodOptions},
@@ -35,7 +34,7 @@ func CorsHandler(allowOrigins []string) Middleware {
}
// ContentTypeHandler checks request for the appropriate media types otherwise returning a http.StatusUnsupportedMediaType error
func ContentTypeHandler(acceptedMediaTypes []string) Middleware {
func ContentTypeHandler(acceptedMediaTypes []string) mux.MiddlewareFunc {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// skip the GET request
@@ -68,7 +67,7 @@ func ContentTypeHandler(acceptedMediaTypes []string) Middleware {
}
// AcceptHeaderHandler checks if the client's response preference is handled
func AcceptHeaderHandler(serverAcceptedTypes []string) Middleware {
func AcceptHeaderHandler(serverAcceptedTypes []string) mux.MiddlewareFunc {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
acceptHeader := r.Header.Get("Accept")
@@ -111,15 +110,3 @@ func AcceptHeaderHandler(serverAcceptedTypes []string) Middleware {
})
}
}
func MiddlewareChain(h http.Handler, mw []Middleware) http.Handler {
if len(mw) < 1 {
return h
}
wrapped := h
for i := len(mw) - 1; i >= 0; i-- {
wrapped = mw[i](wrapped)
}
return wrapped
}

View File

@@ -5,7 +5,6 @@ go_library(
srcs = [
"block.go",
"conversions.go",
"conversions_blob.go",
"conversions_block.go",
"conversions_lightclient.go",
"conversions_state.go",
@@ -35,9 +34,6 @@ go_library(
"//encoding/bytesutil:go_default_library",
"//math: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",
"//proto/prysm/v1alpha1:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",

View File

@@ -365,7 +365,6 @@ type BeaconBlockBodyElectra struct {
ExecutionPayload *ExecutionPayloadElectra `json:"execution_payload"`
BLSToExecutionChanges []*SignedBLSToExecutionChange `json:"bls_to_execution_changes"`
BlobKzgCommitments []string `json:"blob_kzg_commitments"`
ExecutionRequests *ExecutionRequests `json:"execution_requests"`
}
type BlindedBeaconBlockElectra struct {
@@ -404,7 +403,6 @@ type BlindedBeaconBlockBodyElectra struct {
ExecutionPayloadHeader *ExecutionPayloadHeaderElectra `json:"execution_payload_header"`
BLSToExecutionChanges []*SignedBLSToExecutionChange `json:"bls_to_execution_changes"`
BlobKzgCommitments []string `json:"blob_kzg_commitments"`
ExecutionRequests *ExecutionRequests `json:"execution_requests"`
}
type SignedBeaconBlockHeaderContainer struct {
@@ -516,8 +514,6 @@ type ExecutionPayloadDeneb struct {
ExcessBlobGas string `json:"excess_blob_gas"`
}
type ExecutionPayloadElectra = ExecutionPayloadDeneb
type ExecutionPayloadHeaderDeneb struct {
ParentHash string `json:"parent_hash"`
FeeRecipient string `json:"fee_recipient"`
@@ -538,10 +534,48 @@ type ExecutionPayloadHeaderDeneb struct {
ExcessBlobGas string `json:"excess_blob_gas"`
}
type ExecutionPayloadHeaderElectra = ExecutionPayloadHeaderDeneb
type ExecutionRequests struct {
Deposits []*DepositRequest `json:"deposits"`
Withdrawals []*WithdrawalRequest `json:"withdrawals"`
Consolidations []*ConsolidationRequest `json:"consolidations"`
type ExecutionPayloadElectra struct {
ParentHash string `json:"parent_hash"`
FeeRecipient string `json:"fee_recipient"`
StateRoot string `json:"state_root"`
ReceiptsRoot string `json:"receipts_root"`
LogsBloom string `json:"logs_bloom"`
PrevRandao string `json:"prev_randao"`
BlockNumber string `json:"block_number"`
GasLimit string `json:"gas_limit"`
GasUsed string `json:"gas_used"`
Timestamp string `json:"timestamp"`
ExtraData string `json:"extra_data"`
BaseFeePerGas string `json:"base_fee_per_gas"`
BlockHash string `json:"block_hash"`
Transactions []string `json:"transactions"`
Withdrawals []*Withdrawal `json:"withdrawals"`
BlobGasUsed string `json:"blob_gas_used"`
ExcessBlobGas string `json:"excess_blob_gas"`
DepositRequests []*DepositRequest `json:"deposit_requests"`
WithdrawalRequests []*WithdrawalRequest `json:"withdrawal_requests"`
ConsolidationRequests []*ConsolidationRequest `json:"consolidation_requests"`
}
type ExecutionPayloadHeaderElectra struct {
ParentHash string `json:"parent_hash"`
FeeRecipient string `json:"fee_recipient"`
StateRoot string `json:"state_root"`
ReceiptsRoot string `json:"receipts_root"`
LogsBloom string `json:"logs_bloom"`
PrevRandao string `json:"prev_randao"`
BlockNumber string `json:"block_number"`
GasLimit string `json:"gas_limit"`
GasUsed string `json:"gas_used"`
Timestamp string `json:"timestamp"`
ExtraData string `json:"extra_data"`
BaseFeePerGas string `json:"base_fee_per_gas"`
BlockHash string `json:"block_hash"`
TransactionsRoot string `json:"transactions_root"`
WithdrawalsRoot string `json:"withdrawals_root"`
BlobGasUsed string `json:"blob_gas_used"`
ExcessBlobGas string `json:"excess_blob_gas"`
DepositRequestsRoot string `json:"deposit_requests_root"`
WithdrawalRequestsRoot string `json:"withdrawal_requests_root"`
ConsolidationRequestsRoot string `json:"consolidation_requests_root"`
}

View File

@@ -15,7 +15,6 @@ 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"
)
@@ -1476,15 +1475,12 @@ func DepositSnapshotFromConsensus(ds *eth.DepositSnapshot) *DepositSnapshot {
}
}
func PendingDepositsFromConsensus(ds []*eth.PendingDeposit) []*PendingDeposit {
deposits := make([]*PendingDeposit, len(ds))
func PendingBalanceDepositsFromConsensus(ds []*eth.PendingBalanceDeposit) []*PendingBalanceDeposit {
deposits := make([]*PendingBalanceDeposit, len(ds))
for i, d := range ds {
deposits[i] = &PendingDeposit{
Pubkey: hexutil.Encode(d.PublicKey),
WithdrawalCredentials: hexutil.Encode(d.WithdrawalCredentials),
Amount: fmt.Sprintf("%d", d.Amount),
Signature: hexutil.Encode(d.Signature),
Slot: fmt.Sprintf("%d", d.Slot),
deposits[i] = &PendingBalanceDeposit{
Index: fmt.Sprintf("%d", d.Index),
Amount: fmt.Sprintf("%d", d.Amount),
}
}
return deposits
@@ -1512,37 +1508,3 @@ 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

@@ -1,61 +0,0 @@
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,9 +20,6 @@ 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")
@@ -39,9 +36,6 @@ 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")
@@ -2094,31 +2088,27 @@ func (b *BeaconBlockElectra) ToConsensus() (*eth.BeaconBlockElectra, error) {
return nil, server.NewDecodeError(err, "Body.ExecutionPayload.ExcessBlobGas")
}
if b.Body.ExecutionRequests == nil {
return nil, server.NewDecodeError(errors.New("nil execution requests"), "Body.ExequtionRequests")
}
depositRequests := make([]*enginev1.DepositRequest, len(b.Body.ExecutionRequests.Deposits))
for i, d := range b.Body.ExecutionRequests.Deposits {
depositRequests := make([]*enginev1.DepositRequest, len(b.Body.ExecutionPayload.DepositRequests))
for i, d := range b.Body.ExecutionPayload.DepositRequests {
depositRequests[i], err = d.ToConsensus()
if err != nil {
return nil, server.NewDecodeError(err, fmt.Sprintf("Body.ExecutionRequests.Deposits[%d]", i))
return nil, server.NewDecodeError(err, fmt.Sprintf("Body.ExecutionPayload.DepositRequests[%d]", i))
}
}
withdrawalRequests := make([]*enginev1.WithdrawalRequest, len(b.Body.ExecutionRequests.Withdrawals))
for i, w := range b.Body.ExecutionRequests.Withdrawals {
withdrawalRequests := make([]*enginev1.WithdrawalRequest, len(b.Body.ExecutionPayload.WithdrawalRequests))
for i, w := range b.Body.ExecutionPayload.WithdrawalRequests {
withdrawalRequests[i], err = w.ToConsensus()
if err != nil {
return nil, server.NewDecodeError(err, fmt.Sprintf("Body.ExecutionRequests.Withdrawals[%d]", i))
return nil, server.NewDecodeError(err, fmt.Sprintf("Body.ExecutionPayload.WithdrawalRequests[%d]", i))
}
}
consolidationRequests := make([]*enginev1.ConsolidationRequest, len(b.Body.ExecutionRequests.Consolidations))
for i, c := range b.Body.ExecutionRequests.Consolidations {
consolidationRequests := make([]*enginev1.ConsolidationRequest, len(b.Body.ExecutionPayload.ConsolidationRequests))
for i, c := range b.Body.ExecutionPayload.ConsolidationRequests {
consolidationRequests[i], err = c.ToConsensus()
if err != nil {
return nil, server.NewDecodeError(err, fmt.Sprintf("Body.ExecutionRequests.Consolidations[%d]", i))
return nil, server.NewDecodeError(err, fmt.Sprintf("Body.ExecutionPayload.ConsolidationRequests[%d]", i))
}
}
@@ -2161,31 +2151,29 @@ func (b *BeaconBlockElectra) ToConsensus() (*eth.BeaconBlockElectra, error) {
SyncCommitteeSignature: syncCommitteeSig,
},
ExecutionPayload: &enginev1.ExecutionPayloadElectra{
ParentHash: payloadParentHash,
FeeRecipient: payloadFeeRecipient,
StateRoot: payloadStateRoot,
ReceiptsRoot: payloadReceiptsRoot,
LogsBloom: payloadLogsBloom,
PrevRandao: payloadPrevRandao,
BlockNumber: payloadBlockNumber,
GasLimit: payloadGasLimit,
GasUsed: payloadGasUsed,
Timestamp: payloadTimestamp,
ExtraData: payloadExtraData,
BaseFeePerGas: payloadBaseFeePerGas,
BlockHash: payloadBlockHash,
Transactions: txs,
Withdrawals: withdrawals,
BlobGasUsed: payloadBlobGasUsed,
ExcessBlobGas: payloadExcessBlobGas,
ParentHash: payloadParentHash,
FeeRecipient: payloadFeeRecipient,
StateRoot: payloadStateRoot,
ReceiptsRoot: payloadReceiptsRoot,
LogsBloom: payloadLogsBloom,
PrevRandao: payloadPrevRandao,
BlockNumber: payloadBlockNumber,
GasLimit: payloadGasLimit,
GasUsed: payloadGasUsed,
Timestamp: payloadTimestamp,
ExtraData: payloadExtraData,
BaseFeePerGas: payloadBaseFeePerGas,
BlockHash: payloadBlockHash,
Transactions: txs,
Withdrawals: withdrawals,
BlobGasUsed: payloadBlobGasUsed,
ExcessBlobGas: payloadExcessBlobGas,
DepositRequests: depositRequests,
WithdrawalRequests: withdrawalRequests,
ConsolidationRequests: consolidationRequests,
},
BlsToExecutionChanges: blsChanges,
BlobKzgCommitments: blobKzgCommitments,
ExecutionRequests: &enginev1.ExecutionRequests{
Deposits: depositRequests,
Withdrawals: withdrawalRequests,
Consolidations: consolidationRequests,
},
},
}, nil
}
@@ -2395,31 +2383,17 @@ func (b *BlindedBeaconBlockElectra) ToConsensus() (*eth.BlindedBeaconBlockElectr
if err != nil {
return nil, server.NewDecodeError(err, "Body.ExecutionPayload.ExcessBlobGas")
}
if b.Body.ExecutionRequests == nil {
return nil, server.NewDecodeError(errors.New("nil execution requests"), "Body.ExecutionRequests")
payloadDepositRequestsRoot, err := bytesutil.DecodeHexWithLength(b.Body.ExecutionPayloadHeader.DepositRequestsRoot, fieldparams.RootLength)
if err != nil {
return nil, server.NewDecodeError(err, "Body.ExecutionPayloadHeader.DepositRequestsRoot")
}
depositRequests := make([]*enginev1.DepositRequest, len(b.Body.ExecutionRequests.Deposits))
for i, d := range b.Body.ExecutionRequests.Deposits {
depositRequests[i], err = d.ToConsensus()
if err != nil {
return nil, server.NewDecodeError(err, fmt.Sprintf("Body.ExecutionRequests.Deposits[%d]", i))
}
payloadWithdrawalRequestsRoot, err := bytesutil.DecodeHexWithLength(b.Body.ExecutionPayloadHeader.WithdrawalRequestsRoot, fieldparams.RootLength)
if err != nil {
return nil, server.NewDecodeError(err, "Body.ExecutionPayloadHeader.WithdrawalRequestsRoot")
}
withdrawalRequests := make([]*enginev1.WithdrawalRequest, len(b.Body.ExecutionRequests.Withdrawals))
for i, w := range b.Body.ExecutionRequests.Withdrawals {
withdrawalRequests[i], err = w.ToConsensus()
if err != nil {
return nil, server.NewDecodeError(err, fmt.Sprintf("Body.ExecutionRequests.Withdrawals[%d]", i))
}
}
consolidationRequests := make([]*enginev1.ConsolidationRequest, len(b.Body.ExecutionRequests.Consolidations))
for i, c := range b.Body.ExecutionRequests.Consolidations {
consolidationRequests[i], err = c.ToConsensus()
if err != nil {
return nil, server.NewDecodeError(err, fmt.Sprintf("Body.ExecutionRequests.Consolidations[%d]", i))
}
payloadConsolidationRequestsRoot, err := bytesutil.DecodeHexWithLength(b.Body.ExecutionPayloadHeader.ConsolidationRequestsRoot, fieldparams.RootLength)
if err != nil {
return nil, server.NewDecodeError(err, "Body.ExecutionPayloadHeader.ConsolidationRequestsRoot")
}
blsChanges, err := SignedBLSChangesToConsensus(b.Body.BLSToExecutionChanges)
@@ -2462,31 +2436,29 @@ func (b *BlindedBeaconBlockElectra) ToConsensus() (*eth.BlindedBeaconBlockElectr
SyncCommitteeSignature: syncCommitteeSig,
},
ExecutionPayloadHeader: &enginev1.ExecutionPayloadHeaderElectra{
ParentHash: payloadParentHash,
FeeRecipient: payloadFeeRecipient,
StateRoot: payloadStateRoot,
ReceiptsRoot: payloadReceiptsRoot,
LogsBloom: payloadLogsBloom,
PrevRandao: payloadPrevRandao,
BlockNumber: payloadBlockNumber,
GasLimit: payloadGasLimit,
GasUsed: payloadGasUsed,
Timestamp: payloadTimestamp,
ExtraData: payloadExtraData,
BaseFeePerGas: payloadBaseFeePerGas,
BlockHash: payloadBlockHash,
TransactionsRoot: payloadTxsRoot,
WithdrawalsRoot: payloadWithdrawalsRoot,
BlobGasUsed: payloadBlobGasUsed,
ExcessBlobGas: payloadExcessBlobGas,
ParentHash: payloadParentHash,
FeeRecipient: payloadFeeRecipient,
StateRoot: payloadStateRoot,
ReceiptsRoot: payloadReceiptsRoot,
LogsBloom: payloadLogsBloom,
PrevRandao: payloadPrevRandao,
BlockNumber: payloadBlockNumber,
GasLimit: payloadGasLimit,
GasUsed: payloadGasUsed,
Timestamp: payloadTimestamp,
ExtraData: payloadExtraData,
BaseFeePerGas: payloadBaseFeePerGas,
BlockHash: payloadBlockHash,
TransactionsRoot: payloadTxsRoot,
WithdrawalsRoot: payloadWithdrawalsRoot,
BlobGasUsed: payloadBlobGasUsed,
ExcessBlobGas: payloadExcessBlobGas,
DepositRequestsRoot: payloadDepositRequestsRoot,
WithdrawalRequestsRoot: payloadWithdrawalRequestsRoot,
ConsolidationRequestsRoot: payloadConsolidationRequestsRoot,
},
BlsToExecutionChanges: blsChanges,
BlobKzgCommitments: blobKzgCommitments,
ExecutionRequests: &enginev1.ExecutionRequests{
Deposits: depositRequests,
Withdrawals: withdrawalRequests,
Consolidations: consolidationRequests,
},
},
}, nil
}
@@ -2554,8 +2526,6 @@ 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:
@@ -2993,19 +2963,10 @@ func BlindedBeaconBlockElectraFromConsensus(b *eth.BlindedBeaconBlockElectra) (*
ExecutionPayloadHeader: payload,
BLSToExecutionChanges: SignedBLSChangesFromConsensus(b.Body.BlsToExecutionChanges),
BlobKzgCommitments: blobKzgCommitments,
ExecutionRequests: ExecutionRequestsFromConsensus(b.Body.ExecutionRequests),
},
}, nil
}
func ExecutionRequestsFromConsensus(er *enginev1.ExecutionRequests) *ExecutionRequests {
return &ExecutionRequests{
Deposits: DepositRequestsFromConsensus(er.Deposits),
Withdrawals: WithdrawalRequestsFromConsensus(er.Withdrawals),
Consolidations: ConsolidationRequestsFromConsensus(er.Consolidations),
}
}
func SignedBlindedBeaconBlockElectraFromConsensus(b *eth.SignedBlindedBeaconBlockElectra) (*SignedBlindedBeaconBlockElectra, error) {
block, err := BlindedBeaconBlockElectraFromConsensus(b.Message)
if err != nil {
@@ -3048,7 +3009,6 @@ func BeaconBlockElectraFromConsensus(b *eth.BeaconBlockElectra) (*BeaconBlockEle
ExecutionPayload: payload,
BLSToExecutionChanges: SignedBLSChangesFromConsensus(b.Body.BlsToExecutionChanges),
BlobKzgCommitments: blobKzgCommitments,
ExecutionRequests: ExecutionRequestsFromConsensus(b.Body.ExecutionRequests),
},
}, nil
}
@@ -3152,7 +3112,39 @@ func ExecutionPayloadDenebFromConsensus(payload *enginev1.ExecutionPayloadDeneb)
}, nil
}
var ExecutionPayloadElectraFromConsensus = ExecutionPayloadDenebFromConsensus
func ExecutionPayloadElectraFromConsensus(payload *enginev1.ExecutionPayloadElectra) (*ExecutionPayloadElectra, error) {
baseFeePerGas, err := sszBytesToUint256String(payload.BaseFeePerGas)
if err != nil {
return nil, err
}
transactions := make([]string, len(payload.Transactions))
for i, tx := range payload.Transactions {
transactions[i] = hexutil.Encode(tx)
}
return &ExecutionPayloadElectra{
ParentHash: hexutil.Encode(payload.ParentHash),
FeeRecipient: hexutil.Encode(payload.FeeRecipient),
StateRoot: hexutil.Encode(payload.StateRoot),
ReceiptsRoot: hexutil.Encode(payload.ReceiptsRoot),
LogsBloom: hexutil.Encode(payload.LogsBloom),
PrevRandao: hexutil.Encode(payload.PrevRandao),
BlockNumber: fmt.Sprintf("%d", payload.BlockNumber),
GasLimit: fmt.Sprintf("%d", payload.GasLimit),
GasUsed: fmt.Sprintf("%d", payload.GasUsed),
Timestamp: fmt.Sprintf("%d", payload.Timestamp),
ExtraData: hexutil.Encode(payload.ExtraData),
BaseFeePerGas: baseFeePerGas,
BlockHash: hexutil.Encode(payload.BlockHash),
Transactions: transactions,
Withdrawals: WithdrawalsFromConsensus(payload.Withdrawals),
BlobGasUsed: fmt.Sprintf("%d", payload.BlobGasUsed),
ExcessBlobGas: fmt.Sprintf("%d", payload.ExcessBlobGas),
DepositRequests: DepositRequestsFromConsensus(payload.DepositRequests),
WithdrawalRequests: WithdrawalRequestsFromConsensus(payload.WithdrawalRequests),
ConsolidationRequests: ConsolidationRequestsFromConsensus(payload.ConsolidationRequests),
}, nil
}
func ExecutionPayloadHeaderFromConsensus(payload *enginev1.ExecutionPayloadHeader) (*ExecutionPayloadHeader, error) {
baseFeePerGas, err := sszBytesToUint256String(payload.BaseFeePerGas)
@@ -3230,4 +3222,32 @@ func ExecutionPayloadHeaderDenebFromConsensus(payload *enginev1.ExecutionPayload
}, nil
}
var ExecutionPayloadHeaderElectraFromConsensus = ExecutionPayloadHeaderDenebFromConsensus
func ExecutionPayloadHeaderElectraFromConsensus(payload *enginev1.ExecutionPayloadHeaderElectra) (*ExecutionPayloadHeaderElectra, error) {
baseFeePerGas, err := sszBytesToUint256String(payload.BaseFeePerGas)
if err != nil {
return nil, err
}
return &ExecutionPayloadHeaderElectra{
ParentHash: hexutil.Encode(payload.ParentHash),
FeeRecipient: hexutil.Encode(payload.FeeRecipient),
StateRoot: hexutil.Encode(payload.StateRoot),
ReceiptsRoot: hexutil.Encode(payload.ReceiptsRoot),
LogsBloom: hexutil.Encode(payload.LogsBloom),
PrevRandao: hexutil.Encode(payload.PrevRandao),
BlockNumber: fmt.Sprintf("%d", payload.BlockNumber),
GasLimit: fmt.Sprintf("%d", payload.GasLimit),
GasUsed: fmt.Sprintf("%d", payload.GasUsed),
Timestamp: fmt.Sprintf("%d", payload.Timestamp),
ExtraData: hexutil.Encode(payload.ExtraData),
BaseFeePerGas: baseFeePerGas,
BlockHash: hexutil.Encode(payload.BlockHash),
TransactionsRoot: hexutil.Encode(payload.TransactionsRoot),
WithdrawalsRoot: hexutil.Encode(payload.WithdrawalsRoot),
BlobGasUsed: fmt.Sprintf("%d", payload.BlobGasUsed),
ExcessBlobGas: fmt.Sprintf("%d", payload.ExcessBlobGas),
DepositRequestsRoot: hexutil.Encode(payload.DepositRequestsRoot),
WithdrawalRequestsRoot: hexutil.Encode(payload.WithdrawalRequestsRoot),
ConsolidationRequestsRoot: hexutil.Encode(payload.ConsolidationRequestsRoot),
}, nil
}

View File

@@ -1,127 +1,3 @@
package structs
import (
"encoding/json"
"fmt"
"strconv"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/pkg/errors"
v1 "github.com/prysmaticlabs/prysm/v5/proto/eth/v1"
v2 "github.com/prysmaticlabs/prysm/v5/proto/eth/v2"
"github.com/prysmaticlabs/prysm/v5/proto/migration"
)
func LightClientUpdateFromConsensus(update *v2.LightClientUpdate) (*LightClientUpdate, error) {
attestedHeader, err := lightClientHeaderContainerToJSON(update.AttestedHeader)
if err != nil {
return nil, errors.Wrap(err, "could not marshal attested light client header")
}
finalizedHeader, err := lightClientHeaderContainerToJSON(update.FinalizedHeader)
if err != nil {
return nil, errors.Wrap(err, "could not marshal finalized light client header")
}
return &LightClientUpdate{
AttestedHeader: attestedHeader,
NextSyncCommittee: SyncCommitteeFromConsensus(migration.V2SyncCommitteeToV1Alpha1(update.NextSyncCommittee)),
NextSyncCommitteeBranch: branchToJSON(update.NextSyncCommitteeBranch),
FinalizedHeader: finalizedHeader,
FinalityBranch: branchToJSON(update.FinalityBranch),
SyncAggregate: syncAggregateToJSON(update.SyncAggregate),
SignatureSlot: strconv.FormatUint(uint64(update.SignatureSlot), 10),
}, nil
}
func LightClientFinalityUpdateFromConsensus(update *v2.LightClientFinalityUpdate) (*LightClientFinalityUpdate, error) {
attestedHeader, err := lightClientHeaderContainerToJSON(update.AttestedHeader)
if err != nil {
return nil, errors.Wrap(err, "could not marshal attested light client header")
}
finalizedHeader, err := lightClientHeaderContainerToJSON(update.FinalizedHeader)
if err != nil {
return nil, errors.Wrap(err, "could not marshal finalized light client header")
}
return &LightClientFinalityUpdate{
AttestedHeader: attestedHeader,
FinalizedHeader: finalizedHeader,
FinalityBranch: branchToJSON(update.FinalityBranch),
SyncAggregate: syncAggregateToJSON(update.SyncAggregate),
SignatureSlot: strconv.FormatUint(uint64(update.SignatureSlot), 10),
}, nil
}
func LightClientOptimisticUpdateFromConsensus(update *v2.LightClientOptimisticUpdate) (*LightClientOptimisticUpdate, error) {
attestedHeader, err := lightClientHeaderContainerToJSON(update.AttestedHeader)
if err != nil {
return nil, errors.Wrap(err, "could not marshal attested light client header")
}
return &LightClientOptimisticUpdate{
AttestedHeader: attestedHeader,
SyncAggregate: syncAggregateToJSON(update.SyncAggregate),
SignatureSlot: strconv.FormatUint(uint64(update.SignatureSlot), 10),
}, nil
}
func branchToJSON(branchBytes [][]byte) []string {
if branchBytes == nil {
return nil
}
branch := make([]string, len(branchBytes))
for i, root := range branchBytes {
branch[i] = hexutil.Encode(root)
}
return branch
}
func syncAggregateToJSON(input *v1.SyncAggregate) *SyncAggregate {
return &SyncAggregate{
SyncCommitteeBits: hexutil.Encode(input.SyncCommitteeBits),
SyncCommitteeSignature: hexutil.Encode(input.SyncCommitteeSignature),
}
}
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")
}
var header any
switch t := (container.Header).(type) {
case *v2.LightClientHeaderContainer_HeaderAltair:
header = &LightClientHeader{Beacon: BeaconBlockHeaderFromConsensus(migration.V1HeaderToV1Alpha1(beacon))}
case *v2.LightClientHeaderContainer_HeaderCapella:
execution, err := ExecutionPayloadHeaderCapellaFromConsensus(t.HeaderCapella.Execution)
if err != nil {
return nil, err
}
header = &LightClientHeaderCapella{
Beacon: BeaconBlockHeaderFromConsensus(migration.V1HeaderToV1Alpha1(beacon)),
Execution: execution,
ExecutionBranch: branchToJSON(t.HeaderCapella.ExecutionBranch),
}
case *v2.LightClientHeaderContainer_HeaderDeneb:
execution, err := ExecutionPayloadHeaderDenebFromConsensus(t.HeaderDeneb.Execution)
if err != nil {
return nil, err
}
header = &LightClientHeaderDeneb{
Beacon: BeaconBlockHeaderFromConsensus(migration.V1HeaderToV1Alpha1(beacon)),
Execution: execution,
ExecutionBranch: branchToJSON(t.HeaderDeneb.ExecutionBranch),
}
default:
return nil, fmt.Errorf("unsupported header type %T", t)
}
return json.Marshal(header)
}
//

View File

@@ -674,7 +674,7 @@ func BeaconStateElectraFromConsensus(st beaconState.BeaconState) (*BeaconStateEl
if err != nil {
return nil, err
}
srcPayload, ok := execData.Proto().(*enginev1.ExecutionPayloadHeaderDeneb)
srcPayload, ok := execData.Proto().(*enginev1.ExecutionPayloadHeaderElectra)
if !ok {
return nil, errPayloadHeaderNotFound
}
@@ -722,7 +722,7 @@ func BeaconStateElectraFromConsensus(st beaconState.BeaconState) (*BeaconStateEl
if err != nil {
return nil, err
}
pbd, err := st.PendingDeposits()
pbd, err := st.PendingBalanceDeposits()
if err != nil {
return nil, err
}
@@ -770,7 +770,7 @@ func BeaconStateElectraFromConsensus(st beaconState.BeaconState) (*BeaconStateEl
EarliestExitEpoch: fmt.Sprintf("%d", eee),
ConsolidationBalanceToConsume: fmt.Sprintf("%d", cbtc),
EarliestConsolidationEpoch: fmt.Sprintf("%d", ece),
PendingDeposits: PendingDepositsFromConsensus(pbd),
PendingBalanceDeposits: PendingBalanceDepositsFromConsensus(pbd),
PendingPartialWithdrawals: PendingPartialWithdrawalsFromConsensus(ppw),
PendingConsolidations: PendingConsolidationsFromConsensus(pc),
}, nil

View File

@@ -12,12 +12,3 @@ 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

@@ -96,7 +96,21 @@ type LightClientFinalityUpdateEvent struct {
Data *LightClientFinalityUpdate `json:"data"`
}
type LightClientFinalityUpdate struct {
AttestedHeader *BeaconBlockHeader `json:"attested_header"`
FinalizedHeader *BeaconBlockHeader `json:"finalized_header"`
FinalityBranch []string `json:"finality_branch"`
SyncAggregate *SyncAggregate `json:"sync_aggregate"`
SignatureSlot string `json:"signature_slot"`
}
type LightClientOptimisticUpdateEvent struct {
Version string `json:"version"`
Data *LightClientOptimisticUpdate `json:"data"`
}
type LightClientOptimisticUpdate struct {
AttestedHeader *BeaconBlockHeader `json:"attested_header"`
SyncAggregate *SyncAggregate `json:"sync_aggregate"`
SignatureSlot string `json:"signature_slot"`
}

View File

@@ -24,6 +24,11 @@ type LightClientBootstrap struct {
CurrentSyncCommitteeBranch []string `json:"current_sync_committee_branch"`
}
type LightClientBootstrapResponse struct {
Version string `json:"version"`
Data *LightClientBootstrap `json:"data"`
}
type LightClientUpdate struct {
AttestedHeader json.RawMessage `json:"attested_header"`
NextSyncCommittee *SyncCommittee `json:"next_sync_committee,omitempty"`
@@ -34,40 +39,11 @@ type LightClientUpdate struct {
SignatureSlot string `json:"signature_slot"`
}
type LightClientFinalityUpdate struct {
AttestedHeader json.RawMessage `json:"attested_header"`
FinalizedHeader json.RawMessage `json:"finalized_header"`
FinalityBranch []string `json:"finality_branch"`
SyncAggregate *SyncAggregate `json:"sync_aggregate"`
SignatureSlot string `json:"signature_slot"`
}
type LightClientOptimisticUpdate struct {
AttestedHeader json.RawMessage `json:"attested_header"`
SyncAggregate *SyncAggregate `json:"sync_aggregate"`
SignatureSlot string `json:"signature_slot"`
}
type LightClientBootstrapResponse struct {
Version string `json:"version"`
Data *LightClientBootstrap `json:"data"`
}
type LightClientUpdateResponse struct {
type LightClientUpdateWithVersion struct {
Version string `json:"version"`
Data *LightClientUpdate `json:"data"`
}
type LightClientFinalityUpdateResponse struct {
Version string `json:"version"`
Data *LightClientFinalityUpdate `json:"data"`
}
type LightClientOptimisticUpdateResponse struct {
Version string `json:"version"`
Data *LightClientOptimisticUpdate `json:"data"`
}
type LightClientUpdatesByRangeResponse struct {
Updates []*LightClientUpdateResponse `json:"updates"`
Updates []*LightClientUpdateWithVersion `json:"updates"`
}

View File

@@ -257,12 +257,9 @@ type ConsolidationRequest struct {
TargetPubkey string `json:"target_pubkey"`
}
type PendingDeposit struct {
Pubkey string `json:"pubkey"`
WithdrawalCredentials string `json:"withdrawal_credentials"`
Amount string `json:"amount"`
Signature string `json:"signature"`
Slot string `json:"slot"`
type PendingBalanceDeposit struct {
Index string `json:"index"`
Amount string `json:"amount"`
}
type PendingPartialWithdrawal struct {

View File

@@ -176,7 +176,7 @@ type BeaconStateElectra struct {
EarliestExitEpoch string `json:"earliest_exit_epoch"`
ConsolidationBalanceToConsume string `json:"consolidation_balance_to_consume"`
EarliestConsolidationEpoch string `json:"earliest_consolidation_epoch"`
PendingDeposits []*PendingDeposit `json:"pending_deposits"`
PendingBalanceDeposits []*PendingBalanceDeposit `json:"pending_balance_deposits"`
PendingPartialWithdrawals []*PendingPartialWithdrawal `json:"pending_partial_withdrawals"`
PendingConsolidations []*PendingConsolidation `json:"pending_consolidations"`
}

View File

@@ -4,25 +4,26 @@ go_library(
name = "go_default_library",
srcs = [
"feed.go",
"interface.go",
"subscription.go",
],
importpath = "github.com/prysmaticlabs/prysm/v5/async/event",
visibility = ["//visibility:public"],
deps = [
"//time/mclock:go_default_library",
"@com_github_ethereum_go_ethereum//event:go_default_library",
],
deps = ["//time/mclock:go_default_library"],
)
go_test(
name = "go_default_test",
size = "small",
srcs = [
"example_feed_test.go",
"example_scope_test.go",
"example_subscription_test.go",
"feed_test.go",
"subscription_test.go",
],
embed = [":go_default_library"],
deps = ["//testing/require:go_default_library"],
deps = [
"//testing/assert:go_default_library",
"//testing/require:go_default_library",
],
)

View File

@@ -0,0 +1,73 @@
// Copyright 2016 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package event_test
import (
"fmt"
"github.com/prysmaticlabs/prysm/v5/async/event"
)
func ExampleFeed_acknowledgedEvents() {
// This example shows how the return value of Send can be used for request/reply
// interaction between event consumers and producers.
var feed event.Feed
type ackedEvent struct {
i int
ack chan<- struct{}
}
// Consumers wait for events on the feed and acknowledge processing.
done := make(chan struct{})
defer close(done)
for i := 0; i < 3; i++ {
ch := make(chan ackedEvent, 100)
sub := feed.Subscribe(ch)
go func() {
defer sub.Unsubscribe()
for {
select {
case ev := <-ch:
fmt.Println(ev.i) // "process" the event
ev.ack <- struct{}{}
case <-done:
return
}
}
}()
}
// The producer sends values of type ackedEvent with increasing values of i.
// It waits for all consumers to acknowledge before sending the next event.
for i := 0; i < 3; i++ {
acksignal := make(chan struct{})
n := feed.Send(ackedEvent{i, acksignal})
for ack := 0; ack < n; ack++ {
<-acksignal
}
}
// Output:
// 0
// 0
// 0
// 1
// 1
// 1
// 2
// 2
// 2
}

View File

@@ -14,12 +14,241 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
// Package event contains an event feed implementation for process communication.
package event
import (
geth_event "github.com/ethereum/go-ethereum/event"
"errors"
"reflect"
"slices"
"sync"
)
// Feed is a re-export of the go-ethereum event feed.
type Feed = geth_event.Feed
type Subscription = geth_event.Subscription
var errBadChannel = errors.New("event: Subscribe argument does not have sendable channel type")
// Feed implements one-to-many subscriptions where the carrier of events is a channel.
// Values sent to a Feed are delivered to all subscribed channels simultaneously.
//
// Feeds can only be used with a single type. The type is determined by the first Send or
// Subscribe operation. Subsequent calls to these methods panic if the type does not
// match.
//
// The zero value is ready to use.
type Feed struct {
once sync.Once // ensures that init only runs once
sendLock chan struct{} // sendLock has a one-element buffer and is empty when held.It protects sendCases.
removeSub chan interface{} // interrupts Send
sendCases caseList // the active set of select cases used by Send
// The inbox holds newly subscribed channels until they are added to sendCases.
mu sync.Mutex
inbox caseList
etype reflect.Type
}
// This is the index of the first actual subscription channel in sendCases.
// sendCases[0] is a SelectRecv case for the removeSub channel.
const firstSubSendCase = 1
type feedTypeError struct {
got, want reflect.Type
op string
}
func (e feedTypeError) Error() string {
return "event: wrong type in " + e.op + " got " + e.got.String() + ", want " + e.want.String()
}
func (f *Feed) init() {
f.removeSub = make(chan interface{})
f.sendLock = make(chan struct{}, 1)
f.sendLock <- struct{}{}
f.sendCases = caseList{{Chan: reflect.ValueOf(f.removeSub), Dir: reflect.SelectRecv}}
}
// Subscribe adds a channel to the feed. Future sends will be delivered on the channel
// until the subscription is canceled. All channels added must have the same element type.
//
// The channel should have ample buffer space to avoid blocking other subscribers.
// Slow subscribers are not dropped.
func (f *Feed) Subscribe(channel interface{}) Subscription {
f.once.Do(f.init)
chanval := reflect.ValueOf(channel)
chantyp := chanval.Type()
if chantyp.Kind() != reflect.Chan || chantyp.ChanDir()&reflect.SendDir == 0 {
panic(errBadChannel)
}
sub := &feedSub{feed: f, channel: chanval, err: make(chan error, 1)}
f.mu.Lock()
defer f.mu.Unlock()
if !f.typecheck(chantyp.Elem()) {
panic(feedTypeError{op: "Subscribe", got: chantyp, want: reflect.ChanOf(reflect.SendDir, f.etype)})
}
// Add the select case to the inbox.
// The next Send will add it to f.sendCases.
cas := reflect.SelectCase{Dir: reflect.SelectSend, Chan: chanval}
f.inbox = append(f.inbox, cas)
return sub
}
// note: callers must hold f.mu
func (f *Feed) typecheck(typ reflect.Type) bool {
if f.etype == nil {
f.etype = typ
return true
}
// In the event the feed's type is an actual interface, we
// perform an interface conformance check here.
if f.etype.Kind() == reflect.Interface && typ.Implements(f.etype) {
return true
}
return f.etype == typ
}
func (f *Feed) remove(sub *feedSub) {
// Delete from inbox first, which covers channels
// that have not been added to f.sendCases yet.
ch := sub.channel.Interface()
f.mu.Lock()
index := f.inbox.find(ch)
if index != -1 {
f.inbox = f.inbox.delete(index)
f.mu.Unlock()
return
}
f.mu.Unlock()
select {
case f.removeSub <- ch:
// Send will remove the channel from f.sendCases.
case <-f.sendLock:
// No Send is in progress, delete the channel now that we have the send lock.
f.sendCases = f.sendCases.delete(f.sendCases.find(ch))
f.sendLock <- struct{}{}
}
}
// Send delivers to all subscribed channels simultaneously.
// It returns the number of subscribers that the value was sent to.
func (f *Feed) Send(value interface{}) (nsent int) {
rvalue := reflect.ValueOf(value)
f.once.Do(f.init)
<-f.sendLock
// Add new cases from the inbox after taking the send lock.
f.mu.Lock()
f.sendCases = append(f.sendCases, f.inbox...)
f.inbox = nil
if !f.typecheck(rvalue.Type()) {
f.sendLock <- struct{}{}
f.mu.Unlock()
panic(feedTypeError{op: "Send", got: rvalue.Type(), want: f.etype})
}
f.mu.Unlock()
// Set the sent value on all channels.
for i := firstSubSendCase; i < len(f.sendCases); i++ {
f.sendCases[i].Send = rvalue
}
// Send until all channels except removeSub have been chosen. 'cases' tracks a prefix
// of sendCases. When a send succeeds, the corresponding case moves to the end of
// 'cases' and it shrinks by one element.
cases := f.sendCases
for {
// Fast path: try sending without blocking before adding to the select set.
// This should usually succeed if subscribers are fast enough and have free
// buffer space.
for i := firstSubSendCase; i < len(cases); i++ {
if cases[i].Chan.TrySend(rvalue) {
nsent++
cases = cases.deactivate(i)
i--
}
}
if len(cases) == firstSubSendCase {
break
}
// Select on all the receivers, waiting for them to unblock.
chosen, recv, _ := reflect.Select(cases)
if chosen == 0 /* <-f.removeSub */ {
index := f.sendCases.find(recv.Interface())
f.sendCases = f.sendCases.delete(index)
if index >= 0 && index < len(cases) {
// Shrink 'cases' too because the removed case was still active.
cases = f.sendCases[:len(cases)-1]
}
} else {
cases = cases.deactivate(chosen)
nsent++
}
}
// Forget about the sent value and hand off the send lock.
for i := firstSubSendCase; i < len(f.sendCases); i++ {
f.sendCases[i].Send = reflect.Value{}
}
f.sendLock <- struct{}{}
return nsent
}
type feedSub struct {
feed *Feed
channel reflect.Value
errOnce sync.Once
err chan error
}
// Unsubscribe remove feed subscription.
func (sub *feedSub) Unsubscribe() {
sub.errOnce.Do(func() {
sub.feed.remove(sub)
close(sub.err)
})
}
// Err returns error channel.
func (sub *feedSub) Err() <-chan error {
return sub.err
}
type caseList []reflect.SelectCase
// find returns the index of a case containing the given channel.
func (cs caseList) find(channel interface{}) int {
return slices.IndexFunc(cs, func(selectCase reflect.SelectCase) bool {
return selectCase.Chan.Interface() == channel
})
}
// delete removes the given case from cs.
func (cs caseList) delete(index int) caseList {
return append(cs[:index], cs[index+1:]...)
}
// deactivate moves the case at index into the non-accessible portion of the cs slice.
func (cs caseList) deactivate(index int) caseList {
last := len(cs) - 1
cs[index], cs[last] = cs[last], cs[index]
return cs[:last]
}
// func (cs caseList) String() string {
// s := "["
// for i, cas := range cs {
// if i != 0 {
// s += ", "
// }
// switch cas.Dir {
// case reflect.SelectSend:
// s += fmt.Sprintf("%v<-", cas.Chan.Interface())
// case reflect.SelectRecv:
// s += fmt.Sprintf("<-%v", cas.Chan.Interface())
// }
// }
// return s + "]"
// }

509
async/event/feed_test.go Normal file
View File

@@ -0,0 +1,509 @@
// Copyright 2016 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package event
import (
"fmt"
"reflect"
"sync"
"testing"
"time"
"github.com/prysmaticlabs/prysm/v5/testing/assert"
)
func TestFeedPanics(t *testing.T) {
{
var f Feed
f.Send(2)
want := feedTypeError{op: "Send", got: reflect.TypeOf(uint64(0)), want: reflect.TypeOf(0)}
assert.NoError(t, checkPanic(want, func() { f.Send(uint64(2)) }))
// Validate it doesn't deadlock.
assert.NoError(t, checkPanic(want, func() { f.Send(uint64(2)) }))
}
{
var f Feed
ch := make(chan int)
f.Subscribe(ch)
want := feedTypeError{op: "Send", got: reflect.TypeOf(uint64(0)), want: reflect.TypeOf(0)}
assert.NoError(t, checkPanic(want, func() { f.Send(uint64(2)) }))
}
{
var f Feed
f.Send(2)
want := feedTypeError{op: "Subscribe", got: reflect.TypeOf(make(chan uint64)), want: reflect.TypeOf(make(chan<- int))}
assert.NoError(t, checkPanic(want, func() { f.Subscribe(make(chan uint64)) }))
}
{
var f Feed
assert.NoError(t, checkPanic(errBadChannel, func() { f.Subscribe(make(<-chan int)) }))
}
{
var f Feed
assert.NoError(t, checkPanic(errBadChannel, func() { f.Subscribe(0) }))
}
}
func checkPanic(want error, fn func()) (err error) {
defer func() {
panicResult := recover()
if panicResult == nil {
err = fmt.Errorf("didn't panic")
} else if !reflect.DeepEqual(panicResult, want) {
err = fmt.Errorf("panicked with wrong error: got %q, want %q", panicResult, want)
}
}()
fn()
return nil
}
func TestFeed(t *testing.T) {
var feed Feed
var done, subscribed sync.WaitGroup
subscriber := func(i int) {
defer done.Done()
subchan := make(chan int)
sub := feed.Subscribe(subchan)
timeout := time.NewTimer(2 * time.Second)
subscribed.Done()
select {
case v := <-subchan:
if v != 1 {
t.Errorf("%d: received value %d, want 1", i, v)
}
case <-timeout.C:
t.Errorf("%d: receive timeout", i)
}
sub.Unsubscribe()
select {
case _, ok := <-sub.Err():
if ok {
t.Errorf("%d: error channel not closed after unsubscribe", i)
}
case <-timeout.C:
t.Errorf("%d: unsubscribe timeout", i)
}
}
const n = 1000
done.Add(n)
subscribed.Add(n)
for i := 0; i < n; i++ {
go subscriber(i)
}
subscribed.Wait()
if nsent := feed.Send(1); nsent != n {
t.Errorf("first send delivered %d times, want %d", nsent, n)
}
if nsent := feed.Send(2); nsent != 0 {
t.Errorf("second send delivered %d times, want 0", nsent)
}
done.Wait()
}
func TestFeedSubscribeSameChannel(t *testing.T) {
var (
feed Feed
done sync.WaitGroup
ch = make(chan int)
sub1 = feed.Subscribe(ch)
sub2 = feed.Subscribe(ch)
_ = feed.Subscribe(ch)
)
expectSends := func(value, n int) {
if nsent := feed.Send(value); nsent != n {
t.Errorf("send delivered %d times, want %d", nsent, n)
}
done.Done()
}
expectRecv := func(wantValue, n int) {
for i := 0; i < n; i++ {
if v := <-ch; v != wantValue {
t.Errorf("received %d, want %d", v, wantValue)
}
}
}
done.Add(1)
go expectSends(1, 3)
expectRecv(1, 3)
done.Wait()
sub1.Unsubscribe()
done.Add(1)
go expectSends(2, 2)
expectRecv(2, 2)
done.Wait()
sub2.Unsubscribe()
done.Add(1)
go expectSends(3, 1)
expectRecv(3, 1)
done.Wait()
}
func TestFeedSubscribeBlockedPost(_ *testing.T) {
var (
feed Feed
nsends = 2000
ch1 = make(chan int)
ch2 = make(chan int)
wg sync.WaitGroup
)
defer wg.Wait()
feed.Subscribe(ch1)
wg.Add(nsends)
for i := 0; i < nsends; i++ {
go func() {
feed.Send(99)
wg.Done()
}()
}
sub2 := feed.Subscribe(ch2)
defer sub2.Unsubscribe()
// We're done when ch1 has received N times.
// The number of receives on ch2 depends on scheduling.
for i := 0; i < nsends; {
select {
case <-ch1:
i++
case <-ch2:
}
}
}
func TestFeedUnsubscribeBlockedPost(_ *testing.T) {
var (
feed Feed
nsends = 200
chans = make([]chan int, 2000)
subs = make([]Subscription, len(chans))
bchan = make(chan int)
bsub = feed.Subscribe(bchan)
wg sync.WaitGroup
)
for i := range chans {
chans[i] = make(chan int, nsends)
}
// Queue up some Sends. None of these can make progress while bchan isn't read.
wg.Add(nsends)
for i := 0; i < nsends; i++ {
go func() {
feed.Send(99)
wg.Done()
}()
}
// Subscribe the other channels.
for i, ch := range chans {
subs[i] = feed.Subscribe(ch)
}
// Unsubscribe them again.
for _, sub := range subs {
sub.Unsubscribe()
}
// Unblock the Sends.
bsub.Unsubscribe()
wg.Wait()
}
// Checks that unsubscribing a channel during Send works even if that
// channel has already been sent on.
func TestFeedUnsubscribeSentChan(_ *testing.T) {
var (
feed Feed
ch1 = make(chan int)
ch2 = make(chan int)
sub1 = feed.Subscribe(ch1)
sub2 = feed.Subscribe(ch2)
wg sync.WaitGroup
)
defer sub2.Unsubscribe()
wg.Add(1)
go func() {
feed.Send(0)
wg.Done()
}()
// Wait for the value on ch1.
<-ch1
// Unsubscribe ch1, removing it from the send cases.
sub1.Unsubscribe()
// Receive ch2, finishing Send.
<-ch2
wg.Wait()
// Send again. This should send to ch2 only, so the wait group will unblock
// as soon as a value is received on ch2.
wg.Add(1)
go func() {
feed.Send(0)
wg.Done()
}()
<-ch2
wg.Wait()
}
func TestFeedUnsubscribeFromInbox(t *testing.T) {
var (
feed Feed
ch1 = make(chan int)
ch2 = make(chan int)
sub1 = feed.Subscribe(ch1)
sub2 = feed.Subscribe(ch1)
sub3 = feed.Subscribe(ch2)
)
assert.Equal(t, 3, len(feed.inbox))
assert.Equal(t, 1, len(feed.sendCases), "sendCases is non-empty after unsubscribe")
sub1.Unsubscribe()
sub2.Unsubscribe()
sub3.Unsubscribe()
assert.Equal(t, 0, len(feed.inbox), "Inbox is non-empty after unsubscribe")
assert.Equal(t, 1, len(feed.sendCases), "sendCases is non-empty after unsubscribe")
}
func BenchmarkFeedSend1000(b *testing.B) {
var (
done sync.WaitGroup
feed Feed
nsubs = 1000
)
subscriber := func(ch <-chan int) {
for i := 0; i < b.N; i++ {
<-ch
}
done.Done()
}
done.Add(nsubs)
for i := 0; i < nsubs; i++ {
ch := make(chan int, 200)
feed.Subscribe(ch)
go subscriber(ch)
}
// The actual benchmark.
b.ResetTimer()
for i := 0; i < b.N; i++ {
if feed.Send(i) != nsubs {
panic("wrong number of sends")
}
}
b.StopTimer()
done.Wait()
}
func TestFeed_Send(t *testing.T) {
tests := []struct {
name string
evFeed *Feed
testSetup func(fd *Feed, t *testing.T, o interface{})
obj interface{}
expectPanic bool
}{
{
name: "normal struct",
evFeed: new(Feed),
testSetup: func(fd *Feed, t *testing.T, o interface{}) {
testChan := make(chan testFeedWithPointer, 1)
fd.Subscribe(testChan)
},
obj: testFeedWithPointer{
a: new(uint64),
b: new(string),
},
expectPanic: false,
},
{
name: "un-implemented interface",
evFeed: new(Feed),
testSetup: func(fd *Feed, t *testing.T, o interface{}) {
testChan := make(chan testFeedIface, 1)
fd.Subscribe(testChan)
},
obj: testFeedWithPointer{
a: new(uint64),
b: new(string),
},
expectPanic: true,
},
{
name: "semi-implemented interface",
evFeed: new(Feed),
testSetup: func(fd *Feed, t *testing.T, o interface{}) {
testChan := make(chan testFeedIface, 1)
fd.Subscribe(testChan)
},
obj: testFeed2{
a: 0,
b: "",
c: []byte{'A'},
},
expectPanic: true,
},
{
name: "fully-implemented interface",
evFeed: new(Feed),
testSetup: func(fd *Feed, t *testing.T, o interface{}) {
testChan := make(chan testFeedIface)
// Make it unbuffered to allow message to
// pass through
go func() {
a := <-testChan
if !reflect.DeepEqual(a, o) {
t.Errorf("Got = %v, want = %v", a, o)
}
}()
fd.Subscribe(testChan)
},
obj: testFeed{
a: 0,
b: "",
},
expectPanic: false,
},
{
name: "fully-implemented interface with additional methods",
evFeed: new(Feed),
testSetup: func(fd *Feed, t *testing.T, o interface{}) {
testChan := make(chan testFeedIface)
// Make it unbuffered to allow message to
// pass through
go func() {
a := <-testChan
if !reflect.DeepEqual(a, o) {
t.Errorf("Got = %v, want = %v", a, o)
}
}()
fd.Subscribe(testChan)
},
obj: testFeed3{
a: 0,
b: "",
c: []byte{'A'},
d: []byte{'B'},
},
expectPanic: false,
},
{
name: "concrete types implementing the same interface",
evFeed: new(Feed),
testSetup: func(fd *Feed, t *testing.T, o interface{}) {
testChan := make(chan testFeed, 1)
// Make it unbuffered to allow message to
// pass through
go func() {
a := <-testChan
if !reflect.DeepEqual(a, o) {
t.Errorf("Got = %v, want = %v", a, o)
}
}()
fd.Subscribe(testChan)
},
obj: testFeed3{
a: 0,
b: "",
c: []byte{'A'},
d: []byte{'B'},
},
expectPanic: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
if !tt.expectPanic {
t.Errorf("panic triggered when unexpected: %v", r)
}
} else {
if tt.expectPanic {
t.Error("panic not triggered when expected")
}
}
}()
tt.testSetup(tt.evFeed, t, tt.obj)
if gotNsent := tt.evFeed.Send(tt.obj); gotNsent != 1 {
t.Errorf("Send() = %v, want %v", gotNsent, 1)
}
})
}
}
// The following objects below are a collection of different
// struct types to test with.
type testFeed struct {
a uint64
b string
}
func (testFeed) method1() {
}
func (testFeed) method2() {
}
type testFeedWithPointer struct {
a *uint64
b *string
}
type testFeed2 struct {
a uint64
b string
c []byte
}
func (testFeed2) method1() {
}
type testFeed3 struct {
a uint64
b string
c, d []byte
}
func (testFeed3) method1() {
}
func (testFeed3) method2() {
}
func (testFeed3) method3() {
}
type testFeedIface interface {
method1()
method2()
}

View File

@@ -1,8 +0,0 @@
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,6 +28,25 @@ 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

@@ -97,6 +97,7 @@ go_library(
"@com_github_prometheus_client_golang//prometheus:go_default_library",
"@com_github_prometheus_client_golang//prometheus/promauto:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@io_opencensus_go//trace:go_default_library",
"@org_golang_x_sync//errgroup:go_default_library",
],
)

View File

@@ -203,7 +203,7 @@ func (s *Service) HeadState(ctx context.Context) (state.BeaconState, error) {
defer s.headLock.RUnlock()
ok := s.hasHeadState()
span.SetAttributes(trace.BoolAttribute("cache_hit", ok))
span.AddAttributes(trace.BoolAttribute("cache_hit", ok))
if ok {
return s.headState(ctx), nil
@@ -225,7 +225,7 @@ func (s *Service) HeadStateReadOnly(ctx context.Context) (state.ReadOnlyBeaconSt
defer s.headLock.RUnlock()
ok := s.hasHeadState()
span.SetAttributes(trace.BoolAttribute("cache_hit", ok))
span.AddAttributes(trace.BoolAttribute("cache_hit", ok))
if ok {
return s.headStateReadOnly(ctx), nil

View File

@@ -12,9 +12,9 @@ import (
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
payloadattribute "github.com/prysmaticlabs/prysm/v5/consensus-types/payload-attribute"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
"github.com/prysmaticlabs/prysm/v5/time/slots"
"github.com/sirupsen/logrus"
"go.opencensus.io/trace"
)
func (s *Service) isNewHead(r [32]byte) bool {

View File

@@ -7,10 +7,10 @@ import (
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1/attestation"
"github.com/prysmaticlabs/prysm/v5/time/slots"
"go.opencensus.io/trace"
)
// OnAttestation is called whenever an attestation is received, verifies the attestation is valid and saves

View File

@@ -162,10 +162,6 @@ 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")
@@ -187,7 +183,6 @@ func (s *Service) sendLightClientFinalityUpdate(ctx context.Context, signed inte
postState,
signed,
attestedState,
attestedBlock,
finalizedBlock,
)
@@ -198,7 +193,7 @@ func (s *Service) sendLightClientFinalityUpdate(ctx context.Context, signed inte
// Return the result
result := &ethpbv2.LightClientFinalityUpdateWithVersion{
Version: ethpbv2.Version(signed.Version()),
Data: update,
Data: lightclient.CreateLightClientFinalityUpdate(update),
}
// Send event
@@ -213,10 +208,6 @@ 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")
@@ -227,7 +218,6 @@ func (s *Service) sendLightClientOptimisticUpdate(ctx context.Context, signed in
postState,
signed,
attestedState,
attestedBlock,
)
if err != nil {
@@ -237,7 +227,7 @@ func (s *Service) sendLightClientOptimisticUpdate(ctx context.Context, signed in
// Return the result
result := &ethpbv2.LightClientOptimisticUpdateWithVersion{
Version: ethpbv2.Version(signed.Version()),
Data: update,
Data: lightclient.CreateLightClientOptimisticUpdate(update),
}
return s.cfg.StateNotifier.StateFeed().Send(&feed.Event{

View File

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

View File

@@ -98,44 +98,6 @@ 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
@@ -169,7 +131,7 @@ func (msn *MockStateNotifier) ReceivedEvents() []*feed.Event {
}
// StateFeed returns a state feed.
func (msn *MockStateNotifier) StateFeed() event.SubscriberSender {
func (msn *MockStateNotifier) StateFeed() *event.Feed {
msn.feedLock.Lock()
defer msn.feedLock.Unlock()
@@ -197,23 +159,6 @@ func (msn *MockStateNotifier) StateFeed() event.SubscriberSender {
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 {
@@ -228,7 +173,7 @@ type MockOperationNotifier struct {
}
// OperationFeed returns an operation feed.
func (mon *MockOperationNotifier) OperationFeed() event.SubscriberSender {
func (mon *MockOperationNotifier) OperationFeed() *event.Feed {
if mon.feed == nil {
mon.feed = new(event.Feed)
}

View File

@@ -19,7 +19,6 @@ go_library(
"//consensus-types/primitives:go_default_library",
"//encoding/bytesutil:go_default_library",
"//monitoring/tracing:go_default_library",
"//monitoring/tracing/trace:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"@com_github_pkg_errors//:go_default_library",
@@ -27,6 +26,7 @@ go_library(
"@com_github_prometheus_client_golang//prometheus/promauto:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@com_github_urfave_cli_v2//:go_default_library",
"@io_opencensus_go//trace:go_default_library",
],
)

View File

@@ -14,10 +14,10 @@ import (
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
v1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
log "github.com/sirupsen/logrus"
"go.opencensus.io/trace"
)
// ErrNoBuilder is used when builder endpoint is not configured.

View File

@@ -46,7 +46,6 @@ go_library(
"//crypto/rand:go_default_library",
"//encoding/bytesutil:go_default_library",
"//math:go_default_library",
"//monitoring/tracing/trace:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//runtime/version:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
@@ -57,6 +56,7 @@ go_library(
"@com_github_prometheus_client_golang//prometheus/promauto:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@io_k8s_client_go//tools/cache:go_default_library",
"@io_opencensus_go//trace:go_default_library",
],
)

View File

@@ -17,6 +17,6 @@ func trim(queue *cache.FIFO, maxSize uint64) {
}
// popProcessNoopFunc is a no-op function that never returns an error.
func popProcessNoopFunc(_ interface{}, _ bool) error {
func popProcessNoopFunc(_ interface{}) error {
return nil
}

View File

@@ -19,7 +19,6 @@ go_library(
"//crypto/hash:go_default_library",
"//encoding/bytesutil:go_default_library",
"//math:go_default_library",
"//monitoring/tracing/trace:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_pkg_errors//:go_default_library",
@@ -27,6 +26,7 @@ go_library(
"@com_github_prometheus_client_golang//prometheus/promauto:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@com_github_wealdtech_go_bytesutil//:go_default_library",
"@io_opencensus_go//trace:go_default_library",
],
)

View File

@@ -10,10 +10,10 @@ import (
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/cache"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/sirupsen/logrus"
"github.com/wealdtech/go-bytesutil"
"go.opencensus.io/trace"
)
var (
@@ -241,7 +241,7 @@ func (c *Cache) InsertPendingDeposit(ctx context.Context, d *ethpb.Deposit, bloc
c.pendingDeposits = append(c.pendingDeposits,
&ethpb.DepositContainer{Deposit: d, Eth1BlockHeight: blockNum, Index: index, DepositRoot: depositRoot[:]})
pendingDepositsCount.Set(float64(len(c.pendingDeposits)))
span.SetAttributes(trace.Int64Attribute("count", int64(len(c.pendingDeposits))))
span.AddAttributes(trace.Int64Attribute("count", int64(len(c.pendingDeposits))))
}
// Deposits returns the cached internal deposit tree.
@@ -304,7 +304,7 @@ func (c *Cache) PendingContainers(ctx context.Context, untilBlk *big.Int) []*eth
return depositCntrs[i].Index < depositCntrs[j].Index
})
span.SetAttributes(trace.Int64Attribute("count", int64(len(depositCntrs))))
span.AddAttributes(trace.Int64Attribute("count", int64(len(depositCntrs))))
return depositCntrs
}

View File

@@ -10,9 +10,9 @@ import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/sirupsen/logrus"
"go.opencensus.io/trace"
)
var (

View File

@@ -7,8 +7,8 @@ import (
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"go.opencensus.io/trace"
)
// RegistrationCache is used to store the cached results of an Validator Registration request.

View File

@@ -11,7 +11,7 @@ import (
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
lruwrpr "github.com/prysmaticlabs/prysm/v5/cache/lru"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
"go.opencensus.io/trace"
)
var (
@@ -92,17 +92,17 @@ func (c *SkipSlotCache) Get(ctx context.Context, r [32]byte) (state.BeaconState,
delay *= delayFactor
delay = math.Min(delay, maxDelay)
}
span.SetAttributes(trace.BoolAttribute("inProgress", inProgress))
span.AddAttributes(trace.BoolAttribute("inProgress", inProgress))
item, exists := c.cache.Get(r)
if exists && item != nil {
skipSlotCacheHit.Inc()
span.SetAttributes(trace.BoolAttribute("hit", true))
span.AddAttributes(trace.BoolAttribute("hit", true))
return item.(state.BeaconState).Copy(), nil
}
skipSlotCacheMiss.Inc()
span.SetAttributes(trace.BoolAttribute("hit", false))
span.AddAttributes(trace.BoolAttribute("hit", false))
return nil, nil
}

View File

@@ -7,8 +7,10 @@ import (
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
)
// ProcessPreGenesisDeposits processes a deposit for the beacon state before chainstart.
@@ -128,7 +130,7 @@ func ApplyDeposit(beaconState state.BeaconState, data *ethpb.Deposit_Data, verif
return beaconState, nil
}
}
if err := blocks.AddValidatorToRegistry(beaconState, pubKey, withdrawalCredentials, amount); err != nil {
if err := AddValidatorToRegistry(beaconState, pubKey, withdrawalCredentials, amount); err != nil {
return nil, err
}
} else {
@@ -138,3 +140,72 @@ func ApplyDeposit(beaconState state.BeaconState, data *ethpb.Deposit_Data, verif
}
return beaconState, nil
}
// AddValidatorToRegistry updates the beacon state with validator information
// def add_validator_to_registry(state: BeaconState,
//
// pubkey: BLSPubkey,
// withdrawal_credentials: Bytes32,
// amount: uint64) -> None:
// index = get_index_for_new_validator(state)
// validator = get_validator_from_deposit(pubkey, withdrawal_credentials)
// set_or_append_list(state.validators, index, validator)
// set_or_append_list(state.balances, index, 0)
// set_or_append_list(state.previous_epoch_participation, index, ParticipationFlags(0b0000_0000)) // New in Altair
// set_or_append_list(state.current_epoch_participation, index, ParticipationFlags(0b0000_0000)) // New in Altair
// set_or_append_list(state.inactivity_scores, index, uint64(0)) // New in Altair
func AddValidatorToRegistry(beaconState state.BeaconState, pubKey []byte, withdrawalCredentials []byte, amount uint64) error {
val := GetValidatorFromDeposit(pubKey, withdrawalCredentials, amount)
if err := beaconState.AppendValidator(val); err != nil {
return err
}
if err := beaconState.AppendBalance(amount); err != nil {
return err
}
// only active in altair and only when it's a new validator (after append balance)
if beaconState.Version() >= version.Altair {
if err := beaconState.AppendInactivityScore(0); err != nil {
return err
}
if err := beaconState.AppendPreviousParticipationBits(0); err != nil {
return err
}
if err := beaconState.AppendCurrentParticipationBits(0); err != nil {
return err
}
}
return nil
}
// GetValidatorFromDeposit gets a new validator object with provided parameters
//
// def get_validator_from_deposit(pubkey: BLSPubkey, withdrawal_credentials: Bytes32, amount: uint64) -> Validator:
//
// effective_balance = min(amount - amount % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE)
//
// return Validator(
// pubkey=pubkey,
// withdrawal_credentials=withdrawal_credentials,
// activation_eligibility_epoch=FAR_FUTURE_EPOCH,
// activation_epoch=FAR_FUTURE_EPOCH,
// exit_epoch=FAR_FUTURE_EPOCH,
// withdrawable_epoch=FAR_FUTURE_EPOCH,
// effective_balance=effective_balance,
// )
func GetValidatorFromDeposit(pubKey []byte, withdrawalCredentials []byte, amount uint64) *ethpb.Validator {
effectiveBalance := amount - (amount % params.BeaconConfig().EffectiveBalanceIncrement)
if params.BeaconConfig().MaxEffectiveBalance < effectiveBalance {
effectiveBalance = params.BeaconConfig().MaxEffectiveBalance
}
return &ethpb.Validator{
PublicKey: pubKey,
WithdrawalCredentials: withdrawalCredentials,
ActivationEligibilityEpoch: params.BeaconConfig().FarFutureEpoch,
ActivationEpoch: params.BeaconConfig().FarFutureEpoch,
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch,
EffectiveBalance: effectiveBalance,
}
}

View File

@@ -14,78 +14,8 @@ import (
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v5/math"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
)
// AddValidatorToRegistry updates the beacon state with validator information
// def add_validator_to_registry(state: BeaconState,
//
// pubkey: BLSPubkey,
// withdrawal_credentials: Bytes32,
// amount: uint64) -> None:
// index = get_index_for_new_validator(state)
// validator = get_validator_from_deposit(pubkey, withdrawal_credentials)
// set_or_append_list(state.validators, index, validator)
// set_or_append_list(state.balances, index, 0)
// set_or_append_list(state.previous_epoch_participation, index, ParticipationFlags(0b0000_0000)) // New in Altair
// set_or_append_list(state.current_epoch_participation, index, ParticipationFlags(0b0000_0000)) // New in Altair
// set_or_append_list(state.inactivity_scores, index, uint64(0)) // New in Altair
func AddValidatorToRegistry(beaconState state.BeaconState, pubKey []byte, withdrawalCredentials []byte, amount uint64) error {
val := GetValidatorFromDeposit(pubKey, withdrawalCredentials, amount)
if err := beaconState.AppendValidator(val); err != nil {
return err
}
if err := beaconState.AppendBalance(amount); err != nil {
return err
}
// only active in altair and only when it's a new validator (after append balance)
if beaconState.Version() >= version.Altair {
if err := beaconState.AppendInactivityScore(0); err != nil {
return err
}
if err := beaconState.AppendPreviousParticipationBits(0); err != nil {
return err
}
if err := beaconState.AppendCurrentParticipationBits(0); err != nil {
return err
}
}
return nil
}
// GetValidatorFromDeposit gets a new validator object with provided parameters
//
// def get_validator_from_deposit(pubkey: BLSPubkey, withdrawal_credentials: Bytes32, amount: uint64) -> Validator:
//
// effective_balance = min(amount - amount % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE)
//
// return Validator(
// pubkey=pubkey,
// withdrawal_credentials=withdrawal_credentials,
// activation_eligibility_epoch=FAR_FUTURE_EPOCH,
// activation_epoch=FAR_FUTURE_EPOCH,
// exit_epoch=FAR_FUTURE_EPOCH,
// withdrawable_epoch=FAR_FUTURE_EPOCH,
// effective_balance=effective_balance,
// )
func GetValidatorFromDeposit(pubKey []byte, withdrawalCredentials []byte, amount uint64) *ethpb.Validator {
effectiveBalance := amount - (amount % params.BeaconConfig().EffectiveBalanceIncrement)
if params.BeaconConfig().MaxEffectiveBalance < effectiveBalance {
effectiveBalance = params.BeaconConfig().MaxEffectiveBalance
}
return &ethpb.Validator{
PublicKey: pubKey,
WithdrawalCredentials: withdrawalCredentials,
ActivationEligibilityEpoch: params.BeaconConfig().FarFutureEpoch,
ActivationEpoch: params.BeaconConfig().FarFutureEpoch,
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch,
EffectiveBalance: effectiveBalance,
}
}
// ActivateValidatorWithEffectiveBalance updates validator's effective balance, and if it's above MaxEffectiveBalance, validator becomes active in genesis.
func ActivateValidatorWithEffectiveBalance(beaconState state.BeaconState, deposits []*ethpb.Deposit) (state.BeaconState, error) {
for _, d := range deposits {
@@ -133,22 +63,6 @@ func BatchVerifyDepositsSignatures(ctx context.Context, deposits []*ethpb.Deposi
return verified, nil
}
// BatchVerifyPendingDepositsSignatures batch verifies pending deposit signatures.
func BatchVerifyPendingDepositsSignatures(ctx context.Context, deposits []*ethpb.PendingDeposit) (bool, error) {
var err error
domain, err := signing.ComputeDomain(params.BeaconConfig().DomainDeposit, nil, nil)
if err != nil {
return false, err
}
verified := false
if err := verifyPendingDepositDataWithDomain(ctx, deposits, domain); err != nil {
log.WithError(err).Debug("Failed to batch verify deposits signatures, will try individual verify")
verified = true
}
return verified, nil
}
// IsValidDepositSignature returns whether deposit_data is valid
// def is_valid_deposit_signature(pubkey: BLSPubkey, withdrawal_credentials: Bytes32, amount: uint64, signature: BLSSignature) -> bool:
//
@@ -245,44 +159,3 @@ func verifyDepositDataWithDomain(ctx context.Context, deps []*ethpb.Deposit, dom
}
return nil
}
func verifyPendingDepositDataWithDomain(ctx context.Context, deps []*ethpb.PendingDeposit, domain []byte) error {
if len(deps) == 0 {
return nil
}
pks := make([]bls.PublicKey, len(deps))
sigs := make([][]byte, len(deps))
msgs := make([][32]byte, len(deps))
for i, dep := range deps {
if ctx.Err() != nil {
return ctx.Err()
}
if dep == nil {
return errors.New("nil deposit")
}
dpk, err := bls.PublicKeyFromBytes(dep.PublicKey)
if err != nil {
return err
}
pks[i] = dpk
sigs[i] = dep.Signature
depositMessage := &ethpb.DepositMessage{
PublicKey: dep.PublicKey,
WithdrawalCredentials: dep.WithdrawalCredentials,
Amount: dep.Amount,
}
sr, err := signing.ComputeSigningRoot(depositMessage, domain)
if err != nil {
return err
}
msgs[i] = sr
}
verify, err := bls.VerifyMultipleSignatures(sigs, msgs, pks)
if err != nil {
return errors.Errorf("could not verify multiple signatures: %v", err)
}
if !verify {
return errors.New("one or more deposit signatures did not verify")
}
return nil
}

View File

@@ -213,11 +213,6 @@ func NewGenesisBlockForState(ctx context.Context, st state.BeaconState) (interfa
},
BlsToExecutionChanges: make([]*ethpb.SignedBLSToExecutionChange, 0),
BlobKzgCommitments: make([][]byte, 0),
ExecutionRequests: &enginev1.ExecutionRequests{
Withdrawals: make([]*enginev1.WithdrawalRequest, 0),
Deposits: make([]*enginev1.DepositRequest, 0),
Consolidations: make([]*enginev1.ConsolidationRequest, 0),
},
},
},
Signature: params.BeaconConfig().EmptySignature[:],

View File

@@ -32,16 +32,15 @@ go_library(
"//consensus-types/interfaces:go_default_library",
"//consensus-types/primitives:go_default_library",
"//contracts/deposit:go_default_library",
"//crypto/bls/common:go_default_library",
"//encoding/bytesutil:go_default_library",
"//math:go_default_library",
"//monitoring/tracing/trace:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_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",
"@io_opencensus_go//trace:go_default_library",
],
)
@@ -66,13 +65,11 @@ go_test(
"//beacon-chain/core/time:go_default_library",
"//beacon-chain/state:go_default_library",
"//beacon-chain/state/state-native:go_default_library",
"//beacon-chain/state/testing:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//consensus-types/blocks:go_default_library",
"//consensus-types/primitives:go_default_library",
"//crypto/bls:go_default_library",
"//crypto/bls/common:go_default_library",
"//encoding/bytesutil:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",

View File

@@ -11,10 +11,10 @@ import (
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/time/slots"
"go.opencensus.io/trace"
)
// ProcessPendingConsolidations implements the spec definition below. This method makes mutating
@@ -22,29 +22,25 @@ import (
//
// Spec definition:
//
// def process_pending_consolidations(state: BeaconState) -> None:
// next_pending_consolidation = 0
// for pending_consolidation in state.pending_consolidations:
// source_validator = state.validators[pending_consolidation.source_index]
// if source_validator.slashed:
// next_pending_consolidation += 1
// continue
// def process_pending_consolidations(state: BeaconState) -> None:
// if source_validator.withdrawable_epoch > get_current_epoch(state):
// break
//
// next_epoch = Epoch(get_current_epoch(state) + 1)
// next_pending_consolidation = 0
// for pending_consolidation in state.pending_consolidations:
// source_validator = state.validators[pending_consolidation.source_index]
// if source_validator.slashed:
// # Churn any target excess active balance of target and raise its max
// switch_to_compounding_validator(state, pending_consolidation.target_index)
// # Move active balance to target. Excess balance is withdrawable.
// active_balance = get_active_balance(state, pending_consolidation.source_index)
// decrease_balance(state, pending_consolidation.source_index, active_balance)
// increase_balance(state, pending_consolidation.target_index, active_balance)
// next_pending_consolidation += 1
// continue
// if source_validator.withdrawable_epoch > next_epoch:
// break
//
// # Calculate the consolidated balance
// max_effective_balance = get_max_effective_balance(source_validator)
// source_effective_balance = min(state.balances[pending_consolidation.source_index], max_effective_balance)
//
// # Move active balance to target. Excess balance is withdrawable.
// decrease_balance(state, pending_consolidation.source_index, source_effective_balance)
// increase_balance(state, pending_consolidation.target_index, source_effective_balance)
// next_pending_consolidation += 1
//
// state.pending_consolidations = state.pending_consolidations[next_pending_consolidation:]
// state.pending_consolidations = state.pending_consolidations[next_pending_consolidation:]
func ProcessPendingConsolidations(ctx context.Context, st state.BeaconState) error {
_, span := trace.StartSpan(ctx, "electra.ProcessPendingConsolidations")
defer span.End()
@@ -74,19 +70,18 @@ func ProcessPendingConsolidations(ctx context.Context, st state.BeaconState) err
break
}
sourceEffectiveBalance := helpers.ValidatorMaxEffectiveBalance(sourceValidator)
validatorBalance, err := st.BalanceAtIndex(pc.SourceIndex)
if err := SwitchToCompoundingValidator(st, pc.TargetIndex); err != nil {
return err
}
activeBalance, err := st.ActiveBalanceAtIndex(pc.SourceIndex)
if err != nil {
return err
}
if sourceEffectiveBalance > validatorBalance {
sourceEffectiveBalance = validatorBalance
}
if err := helpers.DecreaseBalance(st, pc.SourceIndex, sourceEffectiveBalance); err != nil {
if err := helpers.DecreaseBalance(st, pc.SourceIndex, activeBalance); err != nil {
return err
}
if err := helpers.IncreaseBalance(st, pc.TargetIndex, sourceEffectiveBalance); err != nil {
if err := helpers.IncreaseBalance(st, pc.TargetIndex, activeBalance); err != nil {
return err
}
nextPendingConsolidation++
@@ -106,16 +101,6 @@ func ProcessPendingConsolidations(ctx context.Context, st state.BeaconState) err
// state: BeaconState,
// consolidation_request: ConsolidationRequest
// ) -> None:
// if is_valid_switch_to_compounding_request(state, consolidation_request):
// validator_pubkeys = [v.pubkey for v in state.validators]
// request_source_pubkey = consolidation_request.source_pubkey
// source_index = ValidatorIndex(validator_pubkeys.index(request_source_pubkey))
// switch_to_compounding_validator(state, source_index)
// return
//
// # Verify that source != target, so a consolidation cannot be used as an exit.
// if consolidation_request.source_pubkey == consolidation_request.target_pubkey:
// return
// # If the pending consolidations queue is full, consolidation requests are ignored
// if len(state.pending_consolidations) == PENDING_CONSOLIDATIONS_LIMIT:
// return
@@ -136,6 +121,10 @@ func ProcessPendingConsolidations(ctx context.Context, st state.BeaconState) err
// source_validator = state.validators[source_index]
// target_validator = state.validators[target_index]
//
// # Verify that source != target, so a consolidation cannot be used as an exit.
// if source_index == target_index:
// return
//
// # Verify source withdrawal credentials
// has_correct_credential = has_execution_withdrawal_credential(source_validator)
// is_correct_source_address = (
@@ -171,14 +160,19 @@ func ProcessPendingConsolidations(ctx context.Context, st state.BeaconState) err
// source_index=source_index,
// target_index=target_index
// ))
//
// # Churn any target excess active balance of target and raise its max
// if has_eth1_withdrawal_credential(target_validator):
// switch_to_compounding_validator(state, target_index)
func ProcessConsolidationRequests(ctx context.Context, st state.BeaconState, reqs []*enginev1.ConsolidationRequest) error {
if len(reqs) == 0 || st == nil {
return nil
}
activeBal, err := helpers.TotalActiveBalance(st)
if err != nil {
return err
}
churnLimit := helpers.ConsolidationChurnLimit(primitives.Gwei(activeBal))
if churnLimit <= primitives.Gwei(params.BeaconConfig().MinActivationBalance) {
return nil
}
curEpoch := slots.ToEpoch(st.Slot())
ffe := params.BeaconConfig().FarFutureEpoch
minValWithdrawDelay := params.BeaconConfig().MinValidatorWithdrawabilityDelay
@@ -188,50 +182,25 @@ func ProcessConsolidationRequests(ctx context.Context, st state.BeaconState, req
if ctx.Err() != nil {
return fmt.Errorf("cannot process consolidation requests: %w", ctx.Err())
}
canSwitch, err := IsValidSwitchToCompoundingRequest(ctx, st, cr)
if err != nil {
return fmt.Errorf("failed to validate consolidation request: %w", err)
}
if canSwitch {
srcIdx, ok := st.ValidatorIndexByPubkey(bytesutil.ToBytes48(cr.SourcePubkey))
if !ok {
return errors.New("could not find validator in registry")
}
if err := SwitchToCompoundingValidator(st, srcIdx); err != nil {
return fmt.Errorf("failed to switch to compounding validator: %w", err)
}
return nil
}
sourcePubkey := bytesutil.ToBytes48(cr.SourcePubkey)
targetPubkey := bytesutil.ToBytes48(cr.TargetPubkey)
if sourcePubkey == targetPubkey {
continue
}
if npc, err := st.NumPendingConsolidations(); err != nil {
return fmt.Errorf("failed to fetch number of pending consolidations: %w", err) // This should never happen.
} else if npc >= pcLimit {
return nil
}
activeBal, err := helpers.TotalActiveBalance(st)
if err != nil {
return err
}
churnLimit := helpers.ConsolidationChurnLimit(primitives.Gwei(activeBal))
if churnLimit <= primitives.Gwei(params.BeaconConfig().MinActivationBalance) {
return nil
}
srcIdx, ok := st.ValidatorIndexByPubkey(sourcePubkey)
srcIdx, ok := st.ValidatorIndexByPubkey(bytesutil.ToBytes48(cr.SourcePubkey))
if !ok {
continue
}
tgtIdx, ok := st.ValidatorIndexByPubkey(targetPubkey)
tgtIdx, ok := st.ValidatorIndexByPubkey(bytesutil.ToBytes48(cr.TargetPubkey))
if !ok {
continue
}
if srcIdx == tgtIdx {
continue
}
srcV, err := st.ValidatorAtIndex(srcIdx)
if err != nil {
return fmt.Errorf("failed to fetch source validator: %w", err) // This should never happen.
@@ -279,94 +248,7 @@ func ProcessConsolidationRequests(ctx context.Context, st state.BeaconState, req
if err := st.AppendPendingConsolidation(&eth.PendingConsolidation{SourceIndex: srcIdx, TargetIndex: tgtIdx}); err != nil {
return fmt.Errorf("failed to append pending consolidation: %w", err) // This should never happen.
}
if helpers.HasETH1WithdrawalCredential(tgtV) {
if err := SwitchToCompoundingValidator(st, tgtIdx); err != nil {
return fmt.Errorf("failed to switch to compounding validator: %w", err)
}
}
}
return nil
}
// IsValidSwitchToCompoundingRequest returns true if the given consolidation request is valid for switching to compounding.
//
// Spec code:
//
// def is_valid_switch_to_compounding_request(
//
// state: BeaconState,
// consolidation_request: ConsolidationRequest
//
// ) -> bool:
//
// # Switch to compounding requires source and target be equal
// if consolidation_request.source_pubkey != consolidation_request.target_pubkey:
// return False
//
// # Verify pubkey exists
// source_pubkey = consolidation_request.source_pubkey
// validator_pubkeys = [v.pubkey for v in state.validators]
// if source_pubkey not in validator_pubkeys:
// return False
//
// source_validator = state.validators[ValidatorIndex(validator_pubkeys.index(source_pubkey))]
//
// # Verify request has been authorized
// if source_validator.withdrawal_credentials[12:] != consolidation_request.source_address:
// return False
//
// # Verify source withdrawal credentials
// if not has_eth1_withdrawal_credential(source_validator):
// return False
//
// # Verify the source is active
// current_epoch = get_current_epoch(state)
// if not is_active_validator(source_validator, current_epoch):
// return False
//
// # Verify exit for source have not been initiated
// if source_validator.exit_epoch != FAR_FUTURE_EPOCH:
// return False
//
// return True
func IsValidSwitchToCompoundingRequest(ctx context.Context, st state.BeaconState, req *enginev1.ConsolidationRequest) (bool, error) {
if req.SourcePubkey == nil || req.TargetPubkey == nil {
return false, errors.New("nil source or target pubkey")
}
sourcePubKey := bytesutil.ToBytes48(req.SourcePubkey)
targetPubKey := bytesutil.ToBytes48(req.TargetPubkey)
if sourcePubKey != targetPubKey {
return false, nil
}
srcIdx, ok := st.ValidatorIndexByPubkey(sourcePubKey)
if !ok {
return false, nil
}
srcV, err := st.ValidatorAtIndex(srcIdx)
if err != nil {
return false, err
}
sourceAddress := req.SourceAddress
withdrawalCreds := srcV.WithdrawalCredentials
if len(withdrawalCreds) != 32 || len(sourceAddress) != 20 || !bytes.HasSuffix(withdrawalCreds, sourceAddress) {
return false, nil
}
if !helpers.HasETH1WithdrawalCredential(srcV) {
return false, nil
}
curEpoch := slots.ToEpoch(st.Slot())
if !helpers.IsActiveValidator(srcV, curEpoch) {
return false, nil
}
if srcV.ExitEpoch != params.BeaconConfig().FarFutureEpoch {
return false, nil
}
return true, nil
}

View File

@@ -13,7 +13,6 @@ import (
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/testing/require"
"github.com/prysmaticlabs/prysm/v5/testing/util"
)
func TestProcessPendingConsolidations(t *testing.T) {
@@ -202,6 +201,38 @@ func TestProcessPendingConsolidations(t *testing.T) {
}
}
func stateWithActiveBalanceETH(t *testing.T, balETH uint64) state.BeaconState {
gwei := balETH * 1_000_000_000
balPerVal := params.BeaconConfig().MinActivationBalance
numVals := gwei / balPerVal
vals := make([]*eth.Validator, numVals)
bals := make([]uint64, numVals)
for i := uint64(0); i < numVals; i++ {
wc := make([]byte, 32)
wc[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
wc[31] = byte(i)
vals[i] = &eth.Validator{
ActivationEpoch: 0,
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
EffectiveBalance: balPerVal,
WithdrawalCredentials: wc,
}
bals[i] = balPerVal
}
st, err := state_native.InitializeFromProtoUnsafeElectra(&eth.BeaconStateElectra{
Slot: 10 * params.BeaconConfig().SlotsPerEpoch,
Validators: vals,
Balances: bals,
Fork: &eth.Fork{
CurrentVersion: params.BeaconConfig().ElectraForkVersion,
},
})
require.NoError(t, err)
return st
}
func TestProcessConsolidationRequests(t *testing.T) {
tests := []struct {
name string
@@ -397,96 +428,3 @@ func TestProcessConsolidationRequests(t *testing.T) {
})
}
}
func TestIsValidSwitchToCompoundingRequest(t *testing.T) {
ctx := context.Background()
st, _ := util.DeterministicGenesisStateElectra(t, 1)
t.Run("nil source pubkey", func(t *testing.T) {
ok, err := electra.IsValidSwitchToCompoundingRequest(ctx, st, &enginev1.ConsolidationRequest{
SourcePubkey: nil,
TargetPubkey: []byte{'a'},
})
require.ErrorContains(t, "nil source or target pubkey", err)
require.Equal(t, false, ok)
})
t.Run("nil target pubkey", func(t *testing.T) {
ok, err := electra.IsValidSwitchToCompoundingRequest(ctx, st, &enginev1.ConsolidationRequest{
TargetPubkey: nil,
SourcePubkey: []byte{'a'},
})
require.ErrorContains(t, "nil source or target pubkey", err)
require.Equal(t, false, ok)
})
t.Run("different source and target pubkey", func(t *testing.T) {
ok, err := electra.IsValidSwitchToCompoundingRequest(ctx, st, &enginev1.ConsolidationRequest{
TargetPubkey: []byte{'a'},
SourcePubkey: []byte{'b'},
})
require.NoError(t, err)
require.Equal(t, false, ok)
})
t.Run("source validator not found in state", func(t *testing.T) {
ok, err := electra.IsValidSwitchToCompoundingRequest(ctx, st, &enginev1.ConsolidationRequest{
SourceAddress: make([]byte, 20),
TargetPubkey: []byte{'a'},
SourcePubkey: []byte{'a'},
})
require.NoError(t, err)
require.Equal(t, false, ok)
})
t.Run("incorrect source address", func(t *testing.T) {
v, err := st.ValidatorAtIndex(0)
require.NoError(t, err)
pubkey := v.PublicKey
ok, err := electra.IsValidSwitchToCompoundingRequest(ctx, st, &enginev1.ConsolidationRequest{
SourceAddress: make([]byte, 20),
TargetPubkey: pubkey,
SourcePubkey: pubkey,
})
require.NoError(t, err)
require.Equal(t, false, ok)
})
t.Run("incorrect eth1 withdrawal credential", func(t *testing.T) {
v, err := st.ValidatorAtIndex(0)
require.NoError(t, err)
pubkey := v.PublicKey
wc := v.WithdrawalCredentials
ok, err := electra.IsValidSwitchToCompoundingRequest(ctx, st, &enginev1.ConsolidationRequest{
SourceAddress: wc[12:],
TargetPubkey: pubkey,
SourcePubkey: pubkey,
})
require.NoError(t, err)
require.Equal(t, false, ok)
})
t.Run("is valid compounding request", func(t *testing.T) {
v, err := st.ValidatorAtIndex(0)
require.NoError(t, err)
pubkey := v.PublicKey
wc := v.WithdrawalCredentials
v.WithdrawalCredentials[0] = 1
require.NoError(t, st.UpdateValidatorAtIndex(0, v))
ok, err := electra.IsValidSwitchToCompoundingRequest(ctx, st, &enginev1.ConsolidationRequest{
SourceAddress: wc[12:],
TargetPubkey: pubkey,
SourcePubkey: pubkey,
})
require.NoError(t, err)
require.Equal(t, true, ok)
})
t.Run("already has an exit epoch", func(t *testing.T) {
v, err := st.ValidatorAtIndex(0)
require.NoError(t, err)
pubkey := v.PublicKey
wc := v.WithdrawalCredentials
v.ExitEpoch = 100
require.NoError(t, st.UpdateValidatorAtIndex(0, v))
ok, err := electra.IsValidSwitchToCompoundingRequest(ctx, st, &enginev1.ConsolidationRequest{
SourceAddress: wc[12:],
TargetPubkey: pubkey,
SourcePubkey: pubkey,
})
require.NoError(t, err)
require.Equal(t, false, ok)
})
}

View File

@@ -2,6 +2,7 @@ package electra
import (
"context"
"fmt"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/blocks"
@@ -12,12 +13,12 @@ import (
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/contracts/deposit"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/time/slots"
log "github.com/sirupsen/logrus"
"go.opencensus.io/trace"
)
// ProcessDeposits is one of the operations performed on each processed
@@ -95,41 +96,31 @@ func ProcessDeposit(beaconState state.BeaconState, deposit *ethpb.Deposit, verif
}
// ApplyDeposit
// def apply_deposit(state: BeaconState,
// def apply_deposit(state: BeaconState, pubkey: BLSPubkey, withdrawal_credentials: Bytes32, amount: uint64, signature: BLSSignature) -> None:
// validator_pubkeys = [v.pubkey for v in state.validators]
// if pubkey not in validator_pubkeys:
//
// pubkey: BLSPubkey,
// withdrawal_credentials: Bytes32,
// amount: uint64,
// signature: BLSSignature) -> None:
// validator_pubkeys = [v.pubkey for v in state.validators]
// if pubkey not in validator_pubkeys:
// # Verify the deposit signature (proof of possession) which is not checked by the deposit contract
// if is_valid_deposit_signature(pubkey, withdrawal_credentials, amount, signature):
// add_validator_to_registry(state, pubkey, withdrawal_credentials, Gwei(0)) # [Modified in Electra:EIP7251]
// # [New in Electra:EIP7251]
// state.pending_deposits.append(PendingDeposit(
// pubkey=pubkey,
// withdrawal_credentials=withdrawal_credentials,
// amount=amount,
// signature=signature,
// slot=GENESIS_SLOT,
// ))
// else:
// # Increase balance by deposit amount
// # [Modified in Electra:EIP7251]
// state.pending_deposits.append(PendingDeposit(
// pubkey=pubkey,
// withdrawal_credentials=withdrawal_credentials,
// amount=amount,
// signature=signature,
// slot=GENESIS_SLOT
// ))
// # Verify the deposit signature (proof of possession) which is not checked by the deposit contract
// if is_valid_deposit_signature(pubkey, withdrawal_credentials, amount, signature):
// add_validator_to_registry(state, pubkey, withdrawal_credentials, amount)
//
// else:
//
// # Increase balance by deposit amount
// index = ValidatorIndex(validator_pubkeys.index(pubkey))
// state.pending_balance_deposits.append(PendingBalanceDeposit(index=index, amount=amount)) # [Modified in Electra:EIP-7251]
// # Check if valid deposit switch to compounding credentials
//
// if ( is_compounding_withdrawal_credential(withdrawal_credentials) and has_eth1_withdrawal_credential(state.validators[index])
//
// and is_valid_deposit_signature(pubkey, withdrawal_credentials, amount, signature)
// ):
// switch_to_compounding_validator(state, index)
func ApplyDeposit(beaconState state.BeaconState, data *ethpb.Deposit_Data, verifySignature bool) (state.BeaconState, error) {
pubKey := data.PublicKey
amount := data.Amount
withdrawalCredentials := data.WithdrawalCredentials
signature := data.Signature
_, ok := beaconState.ValidatorIndexByPubkey(bytesutil.ToBytes48(pubKey))
index, ok := beaconState.ValidatorIndexByPubkey(bytesutil.ToBytes48(pubKey))
if !ok {
if verifySignature {
valid, err := IsValidDepositSignature(data)
@@ -140,20 +131,32 @@ func ApplyDeposit(beaconState state.BeaconState, data *ethpb.Deposit_Data, verif
return beaconState, nil
}
}
if err := blocks.AddValidatorToRegistry(beaconState, pubKey, withdrawalCredentials, 0); err != nil { // # [Modified in Electra:EIP7251]
if err := AddValidatorToRegistry(beaconState, pubKey, withdrawalCredentials, amount); err != nil {
return nil, errors.Wrap(err, "could not add validator to registry")
}
}
// no validation on top-ups (phase0 feature). no validation before state change
if err := beaconState.AppendPendingDeposit(&ethpb.PendingDeposit{
PublicKey: pubKey,
WithdrawalCredentials: withdrawalCredentials,
Amount: amount,
Signature: signature,
Slot: params.BeaconConfig().GenesisSlot,
}); err != nil {
return nil, err
} else {
// no validation on top-ups (phase0 feature). no validation before state change
if err := beaconState.AppendPendingBalanceDeposit(index, amount); err != nil {
return nil, err
}
val, err := beaconState.ValidatorAtIndex(index)
if err != nil {
return nil, err
}
if helpers.IsCompoundingWithdrawalCredential(withdrawalCredentials) && helpers.HasETH1WithdrawalCredential(val) {
if verifySignature {
valid, err := IsValidDepositSignature(data)
if err != nil {
return nil, errors.Wrap(err, "could not verify deposit signature")
}
if !valid {
return beaconState, nil
}
}
if err := SwitchToCompoundingValidator(beaconState, index); err != nil {
return nil, errors.Wrap(err, "could not switch to compound validator")
}
}
}
return beaconState, nil
}
@@ -182,80 +185,47 @@ func verifyDepositDataSigningRoot(obj *ethpb.Deposit_Data, domain []byte) error
return deposit.VerifyDepositSignature(obj, domain)
}
// ProcessPendingDeposits implements the spec definition below. This method mutates the state.
// Iterating over `pending_deposits` queue this function runs the following checks before applying pending deposit:
// 1. All Eth1 bridge deposits are processed before the first deposit request gets processed.
// 2. Deposit position in the queue is finalized.
// 3. Deposit does not exceed the `MAX_PENDING_DEPOSITS_PER_EPOCH` limit.
// 4. Deposit does not exceed the activation churn limit.
// ProcessPendingBalanceDeposits implements the spec definition below. This method mutates the state.
//
// Spec definition:
//
// def process_pending_deposits(state: BeaconState) -> None:
// available_for_processing = state.deposit_balance_to_consume + get_activation_exit_churn_limit(state)
// processed_amount = 0
// next_deposit_index = 0
// deposits_to_postpone = []
// is_churn_limit_reached = False
// finalized_slot = compute_start_slot_at_epoch(state.finalized_checkpoint.epoch)
// def process_pending_balance_deposits(state: BeaconState) -> None:
// available_for_processing = state.deposit_balance_to_consume + get_activation_exit_churn_limit(state)
// processed_amount = 0
// next_deposit_index = 0
// deposits_to_postpone = []
//
// for deposit in state.pending_deposits:
// # Do not process deposit requests if Eth1 bridge deposits are not yet applied.
// if (
// # Is deposit request
// deposit.slot > GENESIS_SLOT and
// # There are pending Eth1 bridge deposits
// state.eth1_deposit_index < state.deposit_requests_start_index
// ):
// break
// for deposit in state.pending_balance_deposits:
// validator = state.validators[deposit.index]
// # Validator is exiting, postpone the deposit until after withdrawable epoch
// if validator.exit_epoch < FAR_FUTURE_EPOCH:
// if get_current_epoch(state) <= validator.withdrawable_epoch:
// deposits_to_postpone.append(deposit)
// # Deposited balance will never become active. Increase balance but do not consume churn
// else:
// increase_balance(state, deposit.index, deposit.amount)
// # Validator is not exiting, attempt to process deposit
// else:
// # Deposit does not fit in the churn, no more deposit processing in this epoch.
// if processed_amount + deposit.amount > available_for_processing:
// break
// # Deposit fits in the churn, process it. Increase balance and consume churn.
// else:
// increase_balance(state, deposit.index, deposit.amount)
// processed_amount += deposit.amount
// # Regardless of how the deposit was handled, we move on in the queue.
// next_deposit_index += 1
//
// # Check if deposit has been finalized, otherwise, stop processing.
// if deposit.slot > finalized_slot:
// break
// state.pending_balance_deposits = state.pending_balance_deposits[next_deposit_index:]
//
// # Check if number of processed deposits has not reached the limit, otherwise, stop processing.
// if next_deposit_index >= MAX_PENDING_DEPOSITS_PER_EPOCH:
// break
// if len(state.pending_balance_deposits) == 0:
// state.deposit_balance_to_consume = Gwei(0)
// else:
// state.deposit_balance_to_consume = available_for_processing - processed_amount
//
// # Read validator state
// is_validator_exited = False
// is_validator_withdrawn = False
// validator_pubkeys = [v.pubkey for v in state.validators]
// if deposit.pubkey in validator_pubkeys:
// validator = state.validators[ValidatorIndex(validator_pubkeys.index(deposit.pubkey))]
// is_validator_exited = validator.exit_epoch < FAR_FUTURE_EPOCH
// is_validator_withdrawn = validator.withdrawable_epoch < get_current_epoch(state)
//
// if is_validator_withdrawn:
// # Deposited balance will never become active. Increase balance but do not consume churn
// apply_pending_deposit(state, deposit)
// elif is_validator_exited:
// # Validator is exiting, postpone the deposit until after withdrawable epoch
// deposits_to_postpone.append(deposit)
// else:
// # Check if deposit fits in the churn, otherwise, do no more deposit processing in this epoch.
// is_churn_limit_reached = processed_amount + deposit.amount > available_for_processing
// if is_churn_limit_reached:
// break
//
// # Consume churn and apply deposit.
// processed_amount += deposit.amount
// apply_pending_deposit(state, deposit)
//
// # Regardless of how the deposit was handled, we move on in the queue.
// next_deposit_index += 1
//
// state.pending_deposits = state.pending_deposits[next_deposit_index:]
//
// # Accumulate churn only if the churn limit has been hit.
// if is_churn_limit_reached:
// state.deposit_balance_to_consume = available_for_processing - processed_amount
// else:
// state.deposit_balance_to_consume = Gwei(0)
//
// state.pending_deposits += deposits_to_postpone
func ProcessPendingDeposits(ctx context.Context, st state.BeaconState, activeBalance primitives.Gwei) error {
_, span := trace.StartSpan(ctx, "electra.ProcessPendingDeposits")
// state.pending_balance_deposits += deposits_to_postpone
func ProcessPendingBalanceDeposits(ctx context.Context, st state.BeaconState, activeBalance primitives.Gwei) error {
_, span := trace.StartSpan(ctx, "electra.ProcessPendingBalanceDeposits")
defer span.End()
if st == nil || st.IsNil() {
@@ -268,180 +238,99 @@ func ProcessPendingDeposits(ctx context.Context, st state.BeaconState, activeBal
}
availableForProcessing := depBalToConsume + helpers.ActivationExitChurnLimit(activeBalance)
processedAmount := uint64(0)
nextDepositIndex := uint64(0)
var depositsToPostpone []*eth.PendingDeposit
nextDepositIndex := 0
var depositsToPostpone []*eth.PendingBalanceDeposit
deposits, err := st.PendingDeposits()
deposits, err := st.PendingBalanceDeposits()
if err != nil {
return err
}
isChurnLimitReached := false
finalizedSlot, err := slots.EpochStart(st.FinalizedCheckpoint().Epoch)
if err != nil {
return errors.Wrap(err, "could not get finalized slot")
}
// constants
ffe := params.BeaconConfig().FarFutureEpoch
curEpoch := slots.ToEpoch(st.Slot())
nextEpoch := slots.ToEpoch(st.Slot()) + 1
// Slice to collect deposits needing signature verification
var depositsToVerify []*ethpb.PendingDeposit
for _, pendingDeposit := range deposits {
startIndex, err := st.DepositRequestsStartIndex()
for _, balanceDeposit := range deposits {
v, err := st.ValidatorAtIndexReadOnly(balanceDeposit.Index)
if err != nil {
return errors.Wrap(err, "could not get starting pendingDeposit index")
return fmt.Errorf("failed to fetch validator at index: %w", err)
}
// Do not process pendingDeposit requests if Eth1 bridge deposits are not yet applied.
if pendingDeposit.Slot > params.BeaconConfig().GenesisSlot && st.Eth1DepositIndex() < startIndex {
break
}
// Check if pendingDeposit has been finalized, otherwise, stop processing.
if pendingDeposit.Slot > finalizedSlot {
break
}
// Check if number of processed deposits has not reached the limit, otherwise, stop processing.
if nextDepositIndex >= params.BeaconConfig().MaxPendingDepositsPerEpoch {
break
}
var isValidatorExited bool
var isValidatorWithdrawn bool
index, found := st.ValidatorIndexByPubkey(bytesutil.ToBytes48(pendingDeposit.PublicKey))
if found {
val, err := st.ValidatorAtIndexReadOnly(index)
if err != nil {
return errors.Wrap(err, "could not get validator")
// If the validator is currently exiting, postpone the deposit until after the withdrawable
// epoch.
if v.ExitEpoch() < ffe {
if nextEpoch <= v.WithdrawableEpoch() {
depositsToPostpone = append(depositsToPostpone, balanceDeposit)
} else {
// The deposited balance will never become active. Therefore, we increase the balance but do
// not consume the churn.
if err := helpers.IncreaseBalance(st, balanceDeposit.Index, balanceDeposit.Amount); err != nil {
return err
}
}
isValidatorExited = val.ExitEpoch() < ffe
isValidatorWithdrawn = val.WithdrawableEpoch() < curEpoch
}
if isValidatorWithdrawn {
// Deposited balance will never become active. Increase balance but do not consume churn
if err := ApplyPendingDeposit(ctx, st, pendingDeposit, true); err != nil {
return errors.Wrap(err, "could not apply pending deposit")
}
} else if isValidatorExited {
// Validator is exiting, postpone the pendingDeposit until after withdrawable epoch
depositsToPostpone = append(depositsToPostpone, pendingDeposit)
} else {
// Check if pendingDeposit fits in the churn, otherwise, do no more pendingDeposit processing in this epoch.
isChurnLimitReached = primitives.Gwei(processedAmount+pendingDeposit.Amount) > availableForProcessing
if isChurnLimitReached { // Is churn limit reached?
// Validator is not exiting, attempt to process deposit.
if primitives.Gwei(processedAmount+balanceDeposit.Amount) > availableForProcessing {
break
}
// Consume churn and apply pendingDeposit.
processedAmount += pendingDeposit.Amount
if found {
if err := ApplyPendingDeposit(ctx, st, pendingDeposit, true); err != nil {
return errors.Wrap(err, "could not apply pending deposit")
}
} else {
// Collect deposit for batch signature verification
depositsToVerify = append(depositsToVerify, pendingDeposit)
// Deposit fits in churn, process it. Increase balance and consume churn.
if err := helpers.IncreaseBalance(st, balanceDeposit.Index, balanceDeposit.Amount); err != nil {
return err
}
processedAmount += balanceDeposit.Amount
}
// Regardless of how the pendingDeposit was handled, we move on in the queue.
// Regardless of how the deposit was handled, we move on in the queue.
nextDepositIndex++
}
// Perform batch signature verification on deposits on unfound validators
if len(depositsToVerify) > 0 {
batchVerified, err := blocks.BatchVerifyPendingDepositsSignatures(ctx, depositsToVerify)
if err != nil {
return errors.Wrap(err, "could not batch verify deposit signatures")
}
// Apply deposits that passed verification
for _, dep := range depositsToVerify {
if err := ApplyPendingDeposit(ctx, st, dep, batchVerified); err != nil {
return errors.Wrap(err, "could not apply pending deposit")
}
}
}
// Combined operation:
// - state.pending_deposits = state.pending_deposits[next_deposit_index:]
// - state.pending_deposits += deposits_to_postpone
// However, the number of remaining deposits must be maintained to properly update the pendingDeposit
// - state.pending_balance_deposits = state.pending_balance_deposits[next_deposit_index:]
// - state.pending_balance_deposits += deposits_to_postpone
// However, the number of remaining deposits must be maintained to properly update the deposit
// balance to consume.
numRemainingDeposits := len(deposits[nextDepositIndex:])
deposits = append(deposits[nextDepositIndex:], depositsToPostpone...)
if err := st.SetPendingDeposits(deposits); err != nil {
return errors.Wrap(err, "could not set pending deposits")
if err := st.SetPendingBalanceDeposits(deposits); err != nil {
return err
}
// Accumulate churn only if the churn limit has been hit.
if isChurnLimitReached {
if numRemainingDeposits == 0 {
return st.SetDepositBalanceToConsume(0)
} else {
return st.SetDepositBalanceToConsume(availableForProcessing - primitives.Gwei(processedAmount))
}
return st.SetDepositBalanceToConsume(0)
}
// ApplyPendingDeposit implements the spec definition below.
//
// Spec Definition:
//
// def apply_pending_deposit(state: BeaconState, deposit: PendingDeposit) -> None:
//
// """
// Applies ``deposit`` to the ``state``.
// """
// validator_pubkeys = [v.pubkey for v in state.validators]
// if deposit.pubkey not in validator_pubkeys:
// # Verify the deposit signature (proof of possession) which is not checked by the deposit contract
// if is_valid_deposit_signature(
// deposit.pubkey,
// deposit.withdrawal_credentials,
// deposit.amount,
// deposit.signature
// ):
// add_validator_to_registry(state, deposit.pubkey, deposit.withdrawal_credentials, deposit.amount)
// else:
// validator_index = ValidatorIndex(validator_pubkeys.index(deposit.pubkey))
// # Increase balance
// increase_balance(state, validator_index, deposit.amount)
func ApplyPendingDeposit(ctx context.Context, st state.BeaconState, deposit *ethpb.PendingDeposit, isSigVerified bool) error {
_, span := trace.StartSpan(ctx, "electra.ApplyPendingDeposit")
defer span.End()
index, ok := st.ValidatorIndexByPubkey(bytesutil.ToBytes48(deposit.PublicKey))
if !ok {
var err error
if !isSigVerified {
isSigVerified, err = blocks.IsValidDepositSignature(&ethpb.Deposit_Data{
PublicKey: bytesutil.SafeCopyBytes(deposit.PublicKey),
WithdrawalCredentials: bytesutil.SafeCopyBytes(deposit.WithdrawalCredentials),
Amount: deposit.Amount,
Signature: bytesutil.SafeCopyBytes(deposit.Signature),
})
if err != nil {
return errors.Wrap(err, "could not verify deposit signature")
}
}
if isSigVerified {
if err := blocks.AddValidatorToRegistry(st, deposit.PublicKey, deposit.WithdrawalCredentials, deposit.Amount); err != nil {
return errors.Wrap(err, "could not add validator to registry")
}
}
return nil
}
return helpers.IncreaseBalance(st, index, deposit.Amount)
}
// ProcessDepositRequests is a function as part of electra to process execution layer deposits
func ProcessDepositRequests(ctx context.Context, beaconState state.BeaconState, requests []*enginev1.DepositRequest) (state.BeaconState, error) {
_, span := trace.StartSpan(ctx, "electra.ProcessDepositRequests")
ctx, span := trace.StartSpan(ctx, "electra.ProcessDepositRequests")
defer span.End()
if len(requests) == 0 {
return beaconState, nil
}
var err error
deposits := make([]*ethpb.Deposit, 0)
for _, req := range requests {
if req == nil {
return nil, errors.New("got a nil DepositRequest")
}
deposits = append(deposits, &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: req.Pubkey,
WithdrawalCredentials: req.WithdrawalCredentials,
Amount: req.Amount,
Signature: req.Signature,
},
})
}
batchVerified, err := blocks.BatchVerifyDepositsSignatures(ctx, deposits)
if err != nil {
return nil, errors.Wrap(err, "could not verify deposit signatures in batch")
}
for _, receipt := range requests {
beaconState, err = processDepositRequest(beaconState, receipt)
beaconState, err = processDepositRequest(beaconState, receipt, batchVerified)
if err != nil {
return nil, errors.Wrap(err, "could not apply deposit request")
}
@@ -452,38 +341,31 @@ func ProcessDepositRequests(ctx context.Context, beaconState state.BeaconState,
// processDepositRequest processes the specific deposit receipt
// def process_deposit_request(state: BeaconState, deposit_request: DepositRequest) -> None:
//
// # Set deposit request start index
// if state.deposit_requests_start_index == UNSET_DEPOSIT_REQUEST_START_INDEX:
// state.deposit_requests_start_index = deposit_request.index
// # Set deposit request start index
// if state.deposit_requests_start_index == UNSET_DEPOSIT_REQUEST_START_INDEX:
// state.deposit_requests_start_index = deposit_request.index
//
// state.pending_deposits.append(PendingDeposit(
// pubkey=deposit_request.pubkey,
// withdrawal_credentials=deposit_request.withdrawal_credentials,
// amount=deposit_request.amount,
// signature=deposit_request.signature,
// slot=state.slot,
// ))
func processDepositRequest(beaconState state.BeaconState, request *enginev1.DepositRequest) (state.BeaconState, error) {
// apply_deposit(
// state=state,
// pubkey=deposit_request.pubkey,
// withdrawal_credentials=deposit_request.withdrawal_credentials,
// amount=deposit_request.amount,
// signature=deposit_request.signature,
// )
func processDepositRequest(beaconState state.BeaconState, request *enginev1.DepositRequest, verifySignature bool) (state.BeaconState, error) {
requestsStartIndex, err := beaconState.DepositRequestsStartIndex()
if err != nil {
return nil, errors.Wrap(err, "could not get deposit requests start index")
}
if requestsStartIndex == params.BeaconConfig().UnsetDepositRequestsStartIndex {
if request == nil {
return nil, errors.New("nil deposit request")
}
if err := beaconState.SetDepositRequestsStartIndex(request.Index); err != nil {
return nil, errors.Wrap(err, "could not set deposit requests start index")
}
}
if err := beaconState.AppendPendingDeposit(&ethpb.PendingDeposit{
return ApplyDeposit(beaconState, &ethpb.Deposit_Data{
PublicKey: bytesutil.SafeCopyBytes(request.Pubkey),
Amount: request.Amount,
WithdrawalCredentials: bytesutil.SafeCopyBytes(request.WithdrawalCredentials),
Signature: bytesutil.SafeCopyBytes(request.Signature),
Slot: beaconState.Slot(),
}); err != nil {
return nil, errors.Wrap(err, "could not append deposit request")
}
return beaconState, nil
}, verifySignature)
}

View File

@@ -9,12 +9,10 @@ import (
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/signing"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
state_native "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native"
stateTesting "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/testing"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/crypto/bls"
"github.com/prysmaticlabs/prysm/v5/crypto/bls/common"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
@@ -22,7 +20,7 @@ import (
"github.com/prysmaticlabs/prysm/v5/testing/util"
)
func TestProcessPendingDeposits(t *testing.T) {
func TestProcessPendingBalanceDeposits(t *testing.T) {
tests := []struct {
name string
state state.BeaconState
@@ -50,10 +48,17 @@ func TestProcessPendingDeposits(t *testing.T) {
{
name: "more deposits than balance to consume processes partial deposits",
state: func() state.BeaconState {
amountAvailForProcessing := helpers.ActivationExitChurnLimit(1_000 * 1e9)
depositAmount := uint64(amountAvailForProcessing) / 10
st := stateWithPendingDeposits(t, 1_000, 20, depositAmount)
st := stateWithActiveBalanceETH(t, 1_000)
require.NoError(t, st.SetDepositBalanceToConsume(100))
amountAvailForProcessing := helpers.ActivationExitChurnLimit(1_000 * 1e9)
deps := make([]*eth.PendingBalanceDeposit, 20)
for i := 0; i < len(deps); i += 1 {
deps[i] = &eth.PendingBalanceDeposit{
Amount: uint64(amountAvailForProcessing) / 10,
Index: primitives.ValidatorIndex(i),
}
}
require.NoError(t, st.SetPendingBalanceDeposits(deps))
return st
}(),
check: func(t *testing.T, st state.BeaconState) {
@@ -69,7 +74,7 @@ func TestProcessPendingDeposits(t *testing.T) {
}
// Half of the balance deposits should have been processed.
remaining, err := st.PendingDeposits()
remaining, err := st.PendingBalanceDeposits()
require.NoError(t, err)
require.Equal(t, 10, len(remaining))
},
@@ -77,10 +82,17 @@ func TestProcessPendingDeposits(t *testing.T) {
{
name: "less deposits than balance to consume processes all deposits",
state: func() state.BeaconState {
amountAvailForProcessing := helpers.ActivationExitChurnLimit(1_000 * 1e9)
depositAmount := uint64(amountAvailForProcessing) / 5
st := stateWithPendingDeposits(t, 1_000, 5, depositAmount)
st := stateWithActiveBalanceETH(t, 1_000)
require.NoError(t, st.SetDepositBalanceToConsume(0))
amountAvailForProcessing := helpers.ActivationExitChurnLimit(1_000 * 1e9)
deps := make([]*eth.PendingBalanceDeposit, 5)
for i := 0; i < len(deps); i += 1 {
deps[i] = &eth.PendingBalanceDeposit{
Amount: uint64(amountAvailForProcessing) / 5,
Index: primitives.ValidatorIndex(i),
}
}
require.NoError(t, st.SetPendingBalanceDeposits(deps))
return st
}(),
check: func(t *testing.T, st state.BeaconState) {
@@ -96,74 +108,7 @@ func TestProcessPendingDeposits(t *testing.T) {
}
// All of the balance deposits should have been processed.
remaining, err := st.PendingDeposits()
require.NoError(t, err)
require.Equal(t, 0, len(remaining))
},
},
{
name: "process pending deposit for unknown key, activates new key",
state: func() state.BeaconState {
st := stateWithActiveBalanceETH(t, 0)
sk, err := bls.RandKey()
require.NoError(t, err)
wc := make([]byte, 32)
wc[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
wc[31] = byte(0)
dep := stateTesting.GeneratePendingDeposit(t, sk, params.BeaconConfig().MinActivationBalance, bytesutil.ToBytes32(wc), 0)
require.NoError(t, st.SetPendingDeposits([]*eth.PendingDeposit{dep}))
require.Equal(t, 0, len(st.Validators()))
require.Equal(t, 0, len(st.Balances()))
return st
}(),
check: func(t *testing.T, st state.BeaconState) {
res, err := st.DepositBalanceToConsume()
require.NoError(t, err)
require.Equal(t, primitives.Gwei(0), res)
b, err := st.BalanceAtIndex(0)
require.NoError(t, err)
require.Equal(t, params.BeaconConfig().MinActivationBalance, b)
// All of the balance deposits should have been processed.
remaining, err := st.PendingDeposits()
require.NoError(t, err)
require.Equal(t, 0, len(remaining))
// validator becomes active
require.Equal(t, 1, len(st.Validators()))
require.Equal(t, 1, len(st.Balances()))
},
},
{
name: "process excess balance that uses a point to infinity signature, processed as a topup",
state: func() state.BeaconState {
excessBalance := uint64(100)
st := stateWithActiveBalanceETH(t, 32)
validators := st.Validators()
sk, err := bls.RandKey()
require.NoError(t, err)
wc := make([]byte, 32)
wc[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
wc[31] = byte(0)
validators[0].PublicKey = sk.PublicKey().Marshal()
validators[0].WithdrawalCredentials = wc
dep := stateTesting.GeneratePendingDeposit(t, sk, excessBalance, bytesutil.ToBytes32(wc), 0)
dep.Signature = common.InfiniteSignature[:]
require.NoError(t, st.SetValidators(validators))
st.SaveValidatorIndices()
require.NoError(t, st.SetPendingDeposits([]*eth.PendingDeposit{dep}))
return st
}(),
check: func(t *testing.T, st state.BeaconState) {
res, err := st.DepositBalanceToConsume()
require.NoError(t, err)
require.Equal(t, primitives.Gwei(0), res)
b, err := st.BalanceAtIndex(0)
require.NoError(t, err)
require.Equal(t, params.BeaconConfig().MinActivationBalance+uint64(100), b)
// All of the balance deposits should have been processed.
remaining, err := st.PendingDeposits()
remaining, err := st.PendingBalanceDeposits()
require.NoError(t, err)
require.Equal(t, 0, len(remaining))
},
@@ -171,10 +116,17 @@ func TestProcessPendingDeposits(t *testing.T) {
{
name: "exiting validator deposit postponed",
state: func() state.BeaconState {
amountAvailForProcessing := helpers.ActivationExitChurnLimit(1_000 * 1e9)
depositAmount := uint64(amountAvailForProcessing) / 5
st := stateWithPendingDeposits(t, 1_000, 5, depositAmount)
st := stateWithActiveBalanceETH(t, 1_000)
require.NoError(t, st.SetDepositBalanceToConsume(0))
amountAvailForProcessing := helpers.ActivationExitChurnLimit(1_000 * 1e9)
deps := make([]*eth.PendingBalanceDeposit, 5)
for i := 0; i < len(deps); i += 1 {
deps[i] = &eth.PendingBalanceDeposit{
Amount: uint64(amountAvailForProcessing) / 5,
Index: primitives.ValidatorIndex(i),
}
}
require.NoError(t, st.SetPendingBalanceDeposits(deps))
v, err := st.ValidatorAtIndex(0)
require.NoError(t, err)
v.ExitEpoch = 10
@@ -196,7 +148,7 @@ func TestProcessPendingDeposits(t *testing.T) {
// All of the balance deposits should have been processed, except validator index 0 was
// added back to the pending deposits queue.
remaining, err := st.PendingDeposits()
remaining, err := st.PendingBalanceDeposits()
require.NoError(t, err)
require.Equal(t, 1, len(remaining))
},
@@ -204,7 +156,15 @@ func TestProcessPendingDeposits(t *testing.T) {
{
name: "exited validator balance increased",
state: func() state.BeaconState {
st := stateWithPendingDeposits(t, 1_000, 1, 1_000_000)
st := stateWithActiveBalanceETH(t, 1_000)
deps := make([]*eth.PendingBalanceDeposit, 1)
for i := 0; i < len(deps); i += 1 {
deps[i] = &eth.PendingBalanceDeposit{
Amount: 1_000_000,
Index: primitives.ValidatorIndex(i),
}
}
require.NoError(t, st.SetPendingBalanceDeposits(deps))
v, err := st.ValidatorAtIndex(0)
require.NoError(t, err)
v.ExitEpoch = 2
@@ -222,7 +182,7 @@ func TestProcessPendingDeposits(t *testing.T) {
require.Equal(t, uint64(1_100_000), b)
// All of the balance deposits should have been processed.
remaining, err := st.PendingDeposits()
remaining, err := st.PendingBalanceDeposits()
require.NoError(t, err)
require.Equal(t, 0, len(remaining))
},
@@ -239,7 +199,7 @@ func TestProcessPendingDeposits(t *testing.T) {
tab, err = helpers.TotalActiveBalance(tt.state)
}
require.NoError(t, err)
err = electra.ProcessPendingDeposits(context.TODO(), tt.state, primitives.Gwei(tab))
err = electra.ProcessPendingBalanceDeposits(context.TODO(), tt.state, primitives.Gwei(tab))
require.Equal(t, tt.wantErr, err != nil, "wantErr=%v, got err=%s", tt.wantErr, err)
if tt.check != nil {
tt.check(t, tt.state)
@@ -260,7 +220,7 @@ func TestProcessDepositRequests(t *testing.T) {
})
t.Run("nil request errors", func(t *testing.T) {
_, err = electra.ProcessDepositRequests(context.Background(), st, []*enginev1.DepositRequest{nil})
require.ErrorContains(t, "nil deposit request", err)
require.ErrorContains(t, "got a nil DepositRequest", err)
})
vals := st.Validators()
@@ -270,7 +230,7 @@ func TestProcessDepositRequests(t *testing.T) {
bals := st.Balances()
bals[0] = params.BeaconConfig().MinActivationBalance + 2000
require.NoError(t, st.SetBalances(bals))
require.NoError(t, st.SetPendingDeposits(make([]*eth.PendingDeposit, 0))) // reset pbd as the determinitstic state populates this already
require.NoError(t, st.SetPendingBalanceDeposits(make([]*eth.PendingBalanceDeposit, 0))) // reset pbd as the determinitstic state populates this already
withdrawalCred := make([]byte, 32)
withdrawalCred[0] = params.BeaconConfig().CompoundingWithdrawalPrefixByte
depositMessage := &eth.DepositMessage{
@@ -295,10 +255,11 @@ func TestProcessDepositRequests(t *testing.T) {
st, err = electra.ProcessDepositRequests(context.Background(), st, requests)
require.NoError(t, err)
pbd, err := st.PendingDeposits()
pbd, err := st.PendingBalanceDeposits()
require.NoError(t, err)
require.Equal(t, 1, len(pbd))
require.Equal(t, 2, len(pbd))
require.Equal(t, uint64(1000), pbd[0].Amount)
require.Equal(t, uint64(2000), pbd[1].Amount)
}
func TestProcessDeposit_Electra_Simple(t *testing.T) {
@@ -325,7 +286,7 @@ func TestProcessDeposit_Electra_Simple(t *testing.T) {
require.NoError(t, err)
pdSt, err := electra.ProcessDeposits(context.Background(), st, deps)
require.NoError(t, err)
pbd, err := pdSt.PendingDeposits()
pbd, err := pdSt.PendingBalanceDeposits()
require.NoError(t, err)
require.Equal(t, params.BeaconConfig().MinActivationBalance, pbd[2].Amount)
require.Equal(t, 3, len(pbd))
@@ -400,128 +361,40 @@ func TestApplyDeposit_TopUps_WithBadSignature(t *testing.T) {
require.NoError(t, st.SetValidators(vals))
adSt, err := electra.ApplyDeposit(st, depositData, true)
require.NoError(t, err)
pbd, err := adSt.PendingDeposits()
pbd, err := adSt.PendingBalanceDeposits()
require.NoError(t, err)
require.Equal(t, 1, len(pbd))
require.Equal(t, topUpAmount, pbd[0].Amount)
}
// stateWithActiveBalanceETH generates a mock beacon state given a balance in eth
func stateWithActiveBalanceETH(t *testing.T, balETH uint64) state.BeaconState {
gwei := balETH * 1_000_000_000
balPerVal := params.BeaconConfig().MinActivationBalance
numVals := gwei / balPerVal
vals := make([]*eth.Validator, numVals)
bals := make([]uint64, numVals)
for i := uint64(0); i < numVals; i++ {
wc := make([]byte, 32)
wc[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
wc[31] = byte(i)
vals[i] = &eth.Validator{
ActivationEpoch: 0,
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
EffectiveBalance: balPerVal,
WithdrawalCredentials: wc,
WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch,
}
bals[i] = balPerVal
}
st, err := state_native.InitializeFromProtoUnsafeElectra(&eth.BeaconStateElectra{
Slot: 10 * params.BeaconConfig().SlotsPerEpoch,
Validators: vals,
Balances: bals,
Fork: &eth.Fork{
CurrentVersion: params.BeaconConfig().ElectraForkVersion,
},
})
require.NoError(t, err)
// set some fake finalized checkpoint
require.NoError(t, st.SetFinalizedCheckpoint(&eth.Checkpoint{
Epoch: 0,
Root: make([]byte, 32),
}))
return st
}
// stateWithPendingDeposits with pending deposits and existing ethbalance
func stateWithPendingDeposits(t *testing.T, balETH uint64, numDeposits, amount uint64) state.BeaconState {
st := stateWithActiveBalanceETH(t, balETH)
deps := make([]*eth.PendingDeposit, numDeposits)
validators := st.Validators()
for i := 0; i < len(deps); i += 1 {
sk, err := bls.RandKey()
require.NoError(t, err)
wc := make([]byte, 32)
wc[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
wc[31] = byte(i)
validators[i].PublicKey = sk.PublicKey().Marshal()
validators[i].WithdrawalCredentials = wc
deps[i] = stateTesting.GeneratePendingDeposit(t, sk, amount, bytesutil.ToBytes32(wc), 0)
}
require.NoError(t, st.SetValidators(validators))
st.SaveValidatorIndices()
require.NoError(t, st.SetPendingDeposits(deps))
return st
}
func TestApplyPendingDeposit_TopUp(t *testing.T) {
excessBalance := uint64(100)
st := stateWithActiveBalanceETH(t, 32)
validators := st.Validators()
func TestApplyDeposit_Electra_SwitchToCompoundingValidator(t *testing.T) {
st, _ := util.DeterministicGenesisStateElectra(t, 3)
sk, err := bls.RandKey()
require.NoError(t, err)
wc := make([]byte, 32)
wc[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
wc[31] = byte(0)
validators[0].PublicKey = sk.PublicKey().Marshal()
validators[0].WithdrawalCredentials = wc
dep := stateTesting.GeneratePendingDeposit(t, sk, excessBalance, bytesutil.ToBytes32(wc), 0)
dep.Signature = common.InfiniteSignature[:]
require.NoError(t, st.SetValidators(validators))
st.SaveValidatorIndices()
require.NoError(t, electra.ApplyPendingDeposit(context.Background(), st, dep, false))
b, err := st.BalanceAtIndex(0)
require.NoError(t, err)
require.Equal(t, params.BeaconConfig().MinActivationBalance+uint64(excessBalance), b)
}
func TestApplyPendingDeposit_UnknownKey(t *testing.T) {
st := stateWithActiveBalanceETH(t, 0)
sk, err := bls.RandKey()
require.NoError(t, err)
wc := make([]byte, 32)
wc[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
wc[31] = byte(0)
dep := stateTesting.GeneratePendingDeposit(t, sk, params.BeaconConfig().MinActivationBalance, bytesutil.ToBytes32(wc), 0)
require.Equal(t, 0, len(st.Validators()))
require.NoError(t, electra.ApplyPendingDeposit(context.Background(), st, dep, false))
// activates new validator
require.Equal(t, 1, len(st.Validators()))
b, err := st.BalanceAtIndex(0)
require.NoError(t, err)
require.Equal(t, params.BeaconConfig().MinActivationBalance, b)
}
func TestApplyPendingDeposit_InvalidSignature(t *testing.T) {
st := stateWithActiveBalanceETH(t, 0)
sk, err := bls.RandKey()
require.NoError(t, err)
wc := make([]byte, 32)
wc[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
wc[31] = byte(0)
dep := &eth.PendingDeposit{
withdrawalCred := make([]byte, 32)
withdrawalCred[0] = params.BeaconConfig().CompoundingWithdrawalPrefixByte
depositData := &eth.Deposit_Data{
PublicKey: sk.PublicKey().Marshal(),
WithdrawalCredentials: wc,
Amount: 100,
Amount: 1000,
WithdrawalCredentials: withdrawalCred,
Signature: make([]byte, fieldparams.BLSSignatureLength),
}
require.Equal(t, 0, len(st.Validators()))
require.NoError(t, electra.ApplyPendingDeposit(context.Background(), st, dep, false))
// no validator added
require.Equal(t, 0, len(st.Validators()))
// no topup either
require.Equal(t, 0, len(st.Balances()))
vals := st.Validators()
vals[0].PublicKey = sk.PublicKey().Marshal()
vals[0].WithdrawalCredentials[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
require.NoError(t, st.SetValidators(vals))
bals := st.Balances()
bals[0] = params.BeaconConfig().MinActivationBalance + 2000
require.NoError(t, st.SetBalances(bals))
sr, err := signing.ComputeSigningRoot(depositData, bytesutil.ToBytes(3, 32))
require.NoError(t, err)
sig := sk.Sign(sr[:])
depositData.Signature = sig.Marshal()
adSt, err := electra.ApplyDeposit(st, depositData, false)
require.NoError(t, err)
pbd, err := adSt.PendingBalanceDeposits()
require.NoError(t, err)
require.Equal(t, 2, len(pbd))
require.Equal(t, uint64(1000), pbd[0].Amount)
require.Equal(t, uint64(2000), pbd[1].Amount)
}

View File

@@ -12,7 +12,7 @@ import (
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
"go.opencensus.io/trace"
)
// Re-exports for methods that haven't changed in Electra.
@@ -44,7 +44,7 @@ var (
// process_registry_updates(state)
// process_slashings(state)
// process_eth1_data_reset(state)
// process_pending_deposits(state) # New in EIP7251
// process_pending_balance_deposits(state) # New in EIP7251
// process_pending_consolidations(state) # New in EIP7251
// process_effective_balance_updates(state)
// process_slashings_reset(state)
@@ -94,7 +94,7 @@ func ProcessEpoch(ctx context.Context, state state.BeaconState) error {
return err
}
if err = ProcessPendingDeposits(ctx, state, primitives.Gwei(bp.ActiveCurrentEpoch)); err != nil {
if err = ProcessPendingBalanceDeposits(ctx, state, primitives.Gwei(bp.ActiveCurrentEpoch)); err != nil {
return err
}
if err = ProcessPendingConsolidations(ctx, state); err != nil {

View File

@@ -78,19 +78,23 @@ func ProcessOperations(
return nil, errors.Wrap(err, "could not process bls-to-execution changes")
}
// new in electra
requests, err := bb.ExecutionRequests()
e, err := bb.Execution()
if err != nil {
return nil, errors.Wrap(err, "could not get execution requests")
return nil, errors.Wrap(err, "could not get execution data from block")
}
st, err = ProcessDepositRequests(ctx, st, requests.Deposits)
exe, ok := e.(interfaces.ExecutionDataElectra)
if !ok {
return nil, errors.New("could not cast execution data to electra execution data")
}
st, err = ProcessDepositRequests(ctx, st, exe.DepositRequests())
if err != nil {
return nil, errors.Wrap(err, "could not process deposit receipts")
}
st, err = ProcessWithdrawalRequests(ctx, st, requests.Withdrawals)
st, err = ProcessWithdrawalRequests(ctx, st, exe.WithdrawalRequests())
if err != nil {
return nil, errors.Wrap(err, "could not process execution layer withdrawal requests")
}
if err := ProcessConsolidationRequests(ctx, st, requests.Consolidations); err != nil {
if err := ProcessConsolidationRequests(ctx, st, exe.ConsolidationRequests()); err != nil {
return nil, fmt.Errorf("could not process consolidation requests: %w", err)
}
return st, nil

View File

@@ -57,17 +57,14 @@ func TestProcessEpoch_CanProcessElectra(t *testing.T) {
require.NoError(t, st.SetSlot(10*params.BeaconConfig().SlotsPerEpoch))
require.NoError(t, st.SetDepositBalanceToConsume(100))
amountAvailForProcessing := helpers.ActivationExitChurnLimit(1_000 * 1e9)
validators := st.Validators()
deps := make([]*ethpb.PendingDeposit, 20)
deps := make([]*ethpb.PendingBalanceDeposit, 20)
for i := 0; i < len(deps); i += 1 {
deps[i] = &ethpb.PendingDeposit{
PublicKey: validators[i].PublicKey,
WithdrawalCredentials: validators[i].WithdrawalCredentials,
Amount: uint64(amountAvailForProcessing) / 10,
Slot: 0,
deps[i] = &ethpb.PendingBalanceDeposit{
Amount: uint64(amountAvailForProcessing) / 10,
Index: primitives.ValidatorIndex(i),
}
}
require.NoError(t, st.SetPendingDeposits(deps))
require.NoError(t, st.SetPendingBalanceDeposits(deps))
require.NoError(t, st.SetPendingConsolidations([]*ethpb.PendingConsolidation{
{
SourceIndex: 2,
@@ -111,7 +108,7 @@ func TestProcessEpoch_CanProcessElectra(t *testing.T) {
require.Equal(t, primitives.Gwei(100), res)
// Half of the balance deposits should have been processed.
remaining, err := st.PendingDeposits()
remaining, err := st.PendingBalanceDeposits()
require.NoError(t, err)
require.Equal(t, 10, len(remaining))

View File

@@ -10,6 +10,7 @@ import (
state_native "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/time/slots"
@@ -101,7 +102,7 @@ import (
// earliest_exit_epoch=earliest_exit_epoch,
// consolidation_balance_to_consume=0,
// earliest_consolidation_epoch=compute_activation_exit_epoch(get_current_epoch(pre)),
// pending_deposits=[],
// pending_balance_deposits=[],
// pending_partial_withdrawals=[],
// pending_consolidations=[],
// )
@@ -244,23 +245,26 @@ func UpgradeToElectra(beaconState state.BeaconState) (state.BeaconState, error)
CurrentSyncCommittee: currentSyncCommittee,
NextSyncCommittee: nextSyncCommittee,
LatestExecutionPayloadHeader: &enginev1.ExecutionPayloadHeaderElectra{
ParentHash: payloadHeader.ParentHash(),
FeeRecipient: payloadHeader.FeeRecipient(),
StateRoot: payloadHeader.StateRoot(),
ReceiptsRoot: payloadHeader.ReceiptsRoot(),
LogsBloom: payloadHeader.LogsBloom(),
PrevRandao: payloadHeader.PrevRandao(),
BlockNumber: payloadHeader.BlockNumber(),
GasLimit: payloadHeader.GasLimit(),
GasUsed: payloadHeader.GasUsed(),
Timestamp: payloadHeader.Timestamp(),
ExtraData: payloadHeader.ExtraData(),
BaseFeePerGas: payloadHeader.BaseFeePerGas(),
BlockHash: payloadHeader.BlockHash(),
TransactionsRoot: txRoot,
WithdrawalsRoot: wdRoot,
ExcessBlobGas: excessBlobGas,
BlobGasUsed: blobGasUsed,
ParentHash: payloadHeader.ParentHash(),
FeeRecipient: payloadHeader.FeeRecipient(),
StateRoot: payloadHeader.StateRoot(),
ReceiptsRoot: payloadHeader.ReceiptsRoot(),
LogsBloom: payloadHeader.LogsBloom(),
PrevRandao: payloadHeader.PrevRandao(),
BlockNumber: payloadHeader.BlockNumber(),
GasLimit: payloadHeader.GasLimit(),
GasUsed: payloadHeader.GasUsed(),
Timestamp: payloadHeader.Timestamp(),
ExtraData: payloadHeader.ExtraData(),
BaseFeePerGas: payloadHeader.BaseFeePerGas(),
BlockHash: payloadHeader.BlockHash(),
TransactionsRoot: txRoot,
WithdrawalsRoot: wdRoot,
ExcessBlobGas: excessBlobGas,
BlobGasUsed: blobGasUsed,
DepositRequestsRoot: bytesutil.Bytes32(0), // [New in Electra:EIP6110]
WithdrawalRequestsRoot: bytesutil.Bytes32(0), // [New in Electra:EIP7002]
ConsolidationRequestsRoot: bytesutil.Bytes32(0), // [New in Electra:EIP7251]
},
NextWithdrawalIndex: wi,
NextWithdrawalValidatorIndex: vi,
@@ -272,7 +276,7 @@ func UpgradeToElectra(beaconState state.BeaconState) (state.BeaconState, error)
EarliestExitEpoch: earliestExitEpoch,
ConsolidationBalanceToConsume: helpers.ConsolidationChurnLimit(primitives.Gwei(tab)),
EarliestConsolidationEpoch: helpers.ActivationExitEpoch(slots.ToEpoch(beaconState.Slot())),
PendingDeposits: make([]*ethpb.PendingDeposit, 0),
PendingBalanceDeposits: make([]*ethpb.PendingBalanceDeposit, 0),
PendingPartialWithdrawals: make([]*ethpb.PendingPartialWithdrawal, 0),
PendingConsolidations: make([]*ethpb.PendingConsolidation, 0),
}

View File

@@ -8,6 +8,7 @@ import (
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/testing/require"
@@ -112,21 +113,24 @@ func TestUpgradeToElectra(t *testing.T) {
wdRoot, err := prevHeader.WithdrawalsRoot()
require.NoError(t, err)
wanted := &enginev1.ExecutionPayloadHeaderElectra{
ParentHash: prevHeader.ParentHash(),
FeeRecipient: prevHeader.FeeRecipient(),
StateRoot: prevHeader.StateRoot(),
ReceiptsRoot: prevHeader.ReceiptsRoot(),
LogsBloom: prevHeader.LogsBloom(),
PrevRandao: prevHeader.PrevRandao(),
BlockNumber: prevHeader.BlockNumber(),
GasLimit: prevHeader.GasLimit(),
GasUsed: prevHeader.GasUsed(),
Timestamp: prevHeader.Timestamp(),
ExtraData: prevHeader.ExtraData(),
BaseFeePerGas: prevHeader.BaseFeePerGas(),
BlockHash: prevHeader.BlockHash(),
TransactionsRoot: txRoot,
WithdrawalsRoot: wdRoot,
ParentHash: prevHeader.ParentHash(),
FeeRecipient: prevHeader.FeeRecipient(),
StateRoot: prevHeader.StateRoot(),
ReceiptsRoot: prevHeader.ReceiptsRoot(),
LogsBloom: prevHeader.LogsBloom(),
PrevRandao: prevHeader.PrevRandao(),
BlockNumber: prevHeader.BlockNumber(),
GasLimit: prevHeader.GasLimit(),
GasUsed: prevHeader.GasUsed(),
Timestamp: prevHeader.Timestamp(),
ExtraData: prevHeader.ExtraData(),
BaseFeePerGas: prevHeader.BaseFeePerGas(),
BlockHash: prevHeader.BlockHash(),
TransactionsRoot: txRoot,
WithdrawalsRoot: wdRoot,
DepositRequestsRoot: bytesutil.Bytes32(0),
WithdrawalRequestsRoot: bytesutil.Bytes32(0),
ConsolidationRequestsRoot: bytesutil.Bytes32(0),
}
require.DeepEqual(t, wanted, protoHeader)
@@ -169,10 +173,10 @@ func TestUpgradeToElectra(t *testing.T) {
require.NoError(t, err)
require.Equal(t, helpers.ActivationExitEpoch(slots.ToEpoch(preForkState.Slot())), earliestConsolidationEpoch)
pendingDeposits, err := mSt.PendingDeposits()
pendingBalanceDeposits, err := mSt.PendingBalanceDeposits()
require.NoError(t, err)
require.Equal(t, 2, len(pendingDeposits))
require.Equal(t, uint64(1000), pendingDeposits[1].Amount)
require.Equal(t, 2, len(pendingBalanceDeposits))
require.Equal(t, uint64(1000), pendingBalanceDeposits[1].Amount)
numPendingPartialWithdrawals, err := mSt.NumPendingPartialWithdrawals()
require.NoError(t, err)

View File

@@ -3,21 +3,87 @@ package electra
import (
"errors"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/crypto/bls/common"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
)
// AddValidatorToRegistry updates the beacon state with validator information
// def add_validator_to_registry(state: BeaconState,
//
// pubkey: BLSPubkey,
// withdrawal_credentials: Bytes32,
// amount: uint64) -> None:
// index = get_index_for_new_validator(state)
// validator = get_validator_from_deposit(pubkey, withdrawal_credentials)
// set_or_append_list(state.validators, index, validator)
// set_or_append_list(state.balances, index, 0) # [Modified in Electra:EIP7251]
// set_or_append_list(state.previous_epoch_participation, index, ParticipationFlags(0b0000_0000))
// set_or_append_list(state.current_epoch_participation, index, ParticipationFlags(0b0000_0000))
// set_or_append_list(state.inactivity_scores, index, uint64(0))
// state.pending_balance_deposits.append(PendingBalanceDeposit(index=index, amount=amount)) # [New in Electra:EIP7251]
func AddValidatorToRegistry(beaconState state.BeaconState, pubKey []byte, withdrawalCredentials []byte, amount uint64) error {
val := ValidatorFromDeposit(pubKey, withdrawalCredentials)
if err := beaconState.AppendValidator(val); err != nil {
return err
}
index, ok := beaconState.ValidatorIndexByPubkey(bytesutil.ToBytes48(pubKey))
if !ok {
return errors.New("could not find validator in registry")
}
if err := beaconState.AppendBalance(0); err != nil {
return err
}
if err := beaconState.AppendPendingBalanceDeposit(index, amount); err != nil {
return err
}
if err := beaconState.AppendInactivityScore(0); err != nil {
return err
}
if err := beaconState.AppendPreviousParticipationBits(0); err != nil {
return err
}
return beaconState.AppendCurrentParticipationBits(0)
}
// ValidatorFromDeposit gets a new validator object with provided parameters
//
// def get_validator_from_deposit(pubkey: BLSPubkey, withdrawal_credentials: Bytes32) -> Validator:
//
// return Validator(
// pubkey=pubkey,
// withdrawal_credentials=withdrawal_credentials,
// activation_eligibility_epoch=FAR_FUTURE_EPOCH,
// activation_epoch=FAR_FUTURE_EPOCH,
// exit_epoch=FAR_FUTURE_EPOCH,
// withdrawable_epoch=FAR_FUTURE_EPOCH,
// effective_balance=0, # [Modified in Electra:EIP7251]
//
// )
func ValidatorFromDeposit(pubKey []byte, withdrawalCredentials []byte) *ethpb.Validator {
return &ethpb.Validator{
PublicKey: pubKey,
WithdrawalCredentials: withdrawalCredentials,
ActivationEligibilityEpoch: params.BeaconConfig().FarFutureEpoch,
ActivationEpoch: params.BeaconConfig().FarFutureEpoch,
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch,
EffectiveBalance: 0, // [Modified in Electra:EIP7251]
}
}
// SwitchToCompoundingValidator
//
// Spec definition:
//
// def switch_to_compounding_validator(state: BeaconState, index: ValidatorIndex) -> None:
// validator = state.validators[index]
// validator.withdrawal_credentials = COMPOUNDING_WITHDRAWAL_PREFIX + validator.withdrawal_credentials[1:]
// queue_excess_active_balance(state, index)
// if has_eth1_withdrawal_credential(validator):
// validator.withdrawal_credentials = COMPOUNDING_WITHDRAWAL_PREFIX + validator.withdrawal_credentials[1:]
// queue_excess_active_balance(state, index)
func SwitchToCompoundingValidator(s state.BeaconState, idx primitives.ValidatorIndex) error {
v, err := s.ValidatorAtIndex(idx)
if err != nil {
@@ -26,31 +92,28 @@ func SwitchToCompoundingValidator(s state.BeaconState, idx primitives.ValidatorI
if len(v.WithdrawalCredentials) == 0 {
return errors.New("validator has no withdrawal credentials")
}
v.WithdrawalCredentials[0] = params.BeaconConfig().CompoundingWithdrawalPrefixByte
if err := s.UpdateValidatorAtIndex(idx, v); err != nil {
return err
if helpers.HasETH1WithdrawalCredential(v) {
v.WithdrawalCredentials[0] = params.BeaconConfig().CompoundingWithdrawalPrefixByte
if err := s.UpdateValidatorAtIndex(idx, v); err != nil {
return err
}
return QueueExcessActiveBalance(s, idx)
}
return QueueExcessActiveBalance(s, idx)
return nil
}
// QueueExcessActiveBalance queues validators with balances above the min activation balance and adds to pending deposit.
// QueueExcessActiveBalance queues validators with balances above the min activation balance and adds to pending balance deposit.
//
// Spec definition:
//
// def queue_excess_active_balance(state: BeaconState, index: ValidatorIndex) -> None:
// balance = state.balances[index]
// if balance > MIN_ACTIVATION_BALANCE:
// excess_balance = balance - MIN_ACTIVATION_BALANCE
// state.balances[index] = MIN_ACTIVATION_BALANCE
// validator = state.validators[index]
// state.pending_deposits.append(PendingDeposit(
// pubkey=validator.pubkey,
// withdrawal_credentials=validator.withdrawal_credentials,
// amount=excess_balance,
// signature=bls.G2_POINT_AT_INFINITY,
// slot=GENESIS_SLOT,
// ))
// def queue_excess_active_balance(state: BeaconState, index: ValidatorIndex) -> None:
// balance = state.balances[index]
// if balance > MIN_ACTIVATION_BALANCE:
// excess_balance = balance - MIN_ACTIVATION_BALANCE
// state.balances[index] = MIN_ACTIVATION_BALANCE
// state.pending_balance_deposits.append(
// PendingBalanceDeposit(index=index, amount=excess_balance)
// )
func QueueExcessActiveBalance(s state.BeaconState, idx primitives.ValidatorIndex) error {
bal, err := s.BalanceAtIndex(idx)
if err != nil {
@@ -58,21 +121,11 @@ func QueueExcessActiveBalance(s state.BeaconState, idx primitives.ValidatorIndex
}
if bal > params.BeaconConfig().MinActivationBalance {
val, err := s.ValidatorAtIndex(idx)
if err != nil {
return err
}
excessBalance := bal - params.BeaconConfig().MinActivationBalance
if err := s.UpdateBalancesAtIndex(idx, params.BeaconConfig().MinActivationBalance); err != nil {
return err
}
return s.AppendPendingDeposit(&ethpb.PendingDeposit{
PublicKey: val.PublicKey,
WithdrawalCredentials: val.WithdrawalCredentials,
Amount: excessBalance,
Signature: common.InfiniteSignature[:],
Slot: params.BeaconConfig().GenesisSlot,
})
return s.AppendPendingBalanceDeposit(idx, excessBalance)
}
return nil
}
@@ -81,19 +134,15 @@ func QueueExcessActiveBalance(s state.BeaconState, idx primitives.ValidatorIndex
//
// Spec definition:
//
// def queue_entire_balance_and_reset_validator(state: BeaconState, index: ValidatorIndex) -> None:
// balance = state.balances[index]
// state.balances[index] = 0
// validator = state.validators[index]
// validator.effective_balance = 0
// validator.activation_eligibility_epoch = FAR_FUTURE_EPOCH
// state.pending_deposits.append(PendingDeposit(
// pubkey=validator.pubkey,
// withdrawal_credentials=validator.withdrawal_credentials,
// amount=balance,
// signature=bls.G2_POINT_AT_INFINITY,
// slot=GENESIS_SLOT,
// ))
// def queue_entire_balance_and_reset_validator(state: BeaconState, index: ValidatorIndex) -> None:
// balance = state.balances[index]
// state.balances[index] = 0
// validator = state.validators[index]
// validator.effective_balance = 0
// validator.activation_eligibility_epoch = FAR_FUTURE_EPOCH
// state.pending_balance_deposits.append(
// PendingBalanceDeposit(index=index, amount=balance)
// )
//
//nolint:dupword
func QueueEntireBalanceAndResetValidator(s state.BeaconState, idx primitives.ValidatorIndex) error {
@@ -117,11 +166,5 @@ func QueueEntireBalanceAndResetValidator(s state.BeaconState, idx primitives.Val
return err
}
return s.AppendPendingDeposit(&ethpb.PendingDeposit{
PublicKey: v.PublicKey,
WithdrawalCredentials: v.WithdrawalCredentials,
Amount: bal,
Signature: common.InfiniteSignature[:],
Slot: params.BeaconConfig().GenesisSlot,
})
return s.AppendPendingBalanceDeposit(idx, bal)
}

View File

@@ -6,6 +6,7 @@ import (
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/electra"
state_native "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
@@ -13,6 +14,20 @@ import (
"github.com/prysmaticlabs/prysm/v5/testing/util"
)
func TestAddValidatorToRegistry(t *testing.T) {
st, err := state_native.InitializeFromProtoElectra(&eth.BeaconStateElectra{})
require.NoError(t, err)
require.NoError(t, electra.AddValidatorToRegistry(st, make([]byte, fieldparams.BLSPubkeyLength), make([]byte, fieldparams.RootLength), 100))
balances := st.Balances()
require.Equal(t, 1, len(balances))
require.Equal(t, uint64(0), balances[0])
pbds, err := st.PendingBalanceDeposits()
require.NoError(t, err)
require.Equal(t, 1, len(pbds))
require.Equal(t, uint64(100), pbds[0].Amount)
require.Equal(t, primitives.ValidatorIndex(0), pbds[0].Index)
}
func TestSwitchToCompoundingValidator(t *testing.T) {
s, err := state_native.InitializeFromProtoElectra(&eth.BeaconStateElectra{
Validators: []*eth.Validator{
@@ -45,7 +60,7 @@ func TestSwitchToCompoundingValidator(t *testing.T) {
b, err := s.BalanceAtIndex(1)
require.NoError(t, err)
require.Equal(t, params.BeaconConfig().MinActivationBalance, b, "balance was changed")
pbd, err := s.PendingDeposits()
pbd, err := s.PendingBalanceDeposits()
require.NoError(t, err)
require.Equal(t, 0, len(pbd), "pending balance deposits should be empty")
@@ -54,10 +69,11 @@ func TestSwitchToCompoundingValidator(t *testing.T) {
b, err = s.BalanceAtIndex(2)
require.NoError(t, err)
require.Equal(t, params.BeaconConfig().MinActivationBalance, b, "balance was not changed")
pbd, err = s.PendingDeposits()
pbd, err = s.PendingBalanceDeposits()
require.NoError(t, err)
require.Equal(t, 1, len(pbd), "pending balance deposits should have one element")
require.Equal(t, uint64(100_000), pbd[0].Amount, "pending balance deposit amount is incorrect")
require.Equal(t, primitives.ValidatorIndex(2), pbd[0].Index, "pending balance deposit index is incorrect")
}
func TestQueueEntireBalanceAndResetValidator(t *testing.T) {
@@ -81,10 +97,11 @@ func TestQueueEntireBalanceAndResetValidator(t *testing.T) {
require.NoError(t, err)
require.Equal(t, uint64(0), v.EffectiveBalance, "effective balance was not reset")
require.Equal(t, params.BeaconConfig().FarFutureEpoch, v.ActivationEligibilityEpoch, "activation eligibility epoch was not reset")
pbd, err := s.PendingDeposits()
pbd, err := s.PendingBalanceDeposits()
require.NoError(t, err)
require.Equal(t, 1, len(pbd), "pending balance deposits should have one element")
require.Equal(t, params.BeaconConfig().MinActivationBalance+100_000, pbd[0].Amount, "pending balance deposit amount is incorrect")
require.Equal(t, primitives.ValidatorIndex(0), pbd[0].Index, "pending balance deposit index is incorrect")
}
func TestSwitchToCompoundingValidator_Ok(t *testing.T) {
@@ -97,7 +114,7 @@ func TestSwitchToCompoundingValidator_Ok(t *testing.T) {
require.NoError(t, st.SetBalances(bals))
require.NoError(t, electra.SwitchToCompoundingValidator(st, 0))
pbd, err := st.PendingDeposits()
pbd, err := st.PendingBalanceDeposits()
require.NoError(t, err)
require.Equal(t, uint64(1010), pbd[0].Amount) // appends it at the end
val, err := st.ValidatorAtIndex(0)
@@ -115,7 +132,7 @@ func TestQueueExcessActiveBalance_Ok(t *testing.T) {
err := electra.QueueExcessActiveBalance(st, 0)
require.NoError(t, err)
pbd, err := st.PendingDeposits()
pbd, err := st.PendingBalanceDeposits()
require.NoError(t, err)
require.Equal(t, uint64(1000), pbd[0].Amount) // appends it at the end
@@ -132,7 +149,7 @@ func TestQueueEntireBalanceAndResetValidator_Ok(t *testing.T) {
err := electra.QueueEntireBalanceAndResetValidator(st, 0)
require.NoError(t, err)
pbd, err := st.PendingDeposits()
pbd, err := st.PendingBalanceDeposits()
require.NoError(t, err)
require.Equal(t, 1, len(pbd))
require.Equal(t, params.BeaconConfig().MinActivationBalance-1000, pbd[0].Amount)

View File

@@ -12,11 +12,11 @@ import (
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/time/slots"
log "github.com/sirupsen/logrus"
"go.opencensus.io/trace"
)
// ProcessWithdrawalRequests processes the validator withdrawals from the provided execution payload

View File

@@ -177,27 +177,18 @@ func ProcessSlashings(st state.BeaconState, slashingMultiplier uint64) (state.Be
// below equally.
increment := params.BeaconConfig().EffectiveBalanceIncrement
minSlashing := math.Min(totalSlashing*slashingMultiplier, totalBalance)
bals := st.Balances()
changed := false
err = st.ReadFromEveryValidator(func(idx int, val state.ReadOnlyValidator) error {
err = st.ApplyToEveryValidator(func(idx int, val state.ReadOnlyValidator) (newVal *ethpb.Validator, err error) {
correctEpoch := (currentEpoch + exitLength/2) == val.WithdrawableEpoch()
if val.Slashed() && correctEpoch {
penaltyNumerator := val.EffectiveBalance() / increment * minSlashing
penalty := penaltyNumerator / totalBalance * increment
bals[idx] = helpers.DecreaseBalanceWithVal(bals[idx], penalty)
changed = true
if err = helpers.DecreaseBalance(st, primitives.ValidatorIndex(idx), penalty); err != nil {
return
}
}
return nil
return
})
if err != nil {
return nil, err
}
if changed {
if err := st.SetBalances(bals); err != nil {
return nil, err
}
}
return st, nil
return st, err
}
// ProcessEth1DataReset processes updates to ETH1 data votes during epoch processing.

View File

@@ -31,6 +31,7 @@ go_library(
"//time/slots:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
"@io_opencensus_go//trace:go_default_library",
],
)

View File

@@ -11,7 +11,7 @@ import (
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
"go.opencensus.io/trace"
)
// New gets called at the beginning of process epoch cycle to return

View File

@@ -5,7 +5,9 @@ import (
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/math"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
)
// ProcessSlashingsPrecompute processes the slashed validators during epoch processing.
@@ -42,18 +44,17 @@ func ProcessSlashingsPrecompute(s state.BeaconState, pBal *Balance) error {
}
increment := params.BeaconConfig().EffectiveBalanceIncrement
bals := s.Balances()
validatorFunc := func(idx int, val state.ReadOnlyValidator) error {
validatorFunc := func(idx int, val state.ReadOnlyValidator) (newVal *ethpb.Validator, err error) {
correctEpoch := epochToWithdraw == val.WithdrawableEpoch()
if val.Slashed() && correctEpoch {
penaltyNumerator := val.EffectiveBalance() / increment * minSlashing
penalty := penaltyNumerator / pBal.ActiveCurrentEpoch * increment
bals[idx] = helpers.DecreaseBalanceWithVal(bals[idx], penalty)
if err = helpers.DecreaseBalance(s, primitives.ValidatorIndex(idx), penalty); err != nil {
return
}
}
return nil
return
}
if err := s.ReadFromEveryValidator(validatorFunc); err != nil {
return err
}
return s.SetBalances(bals)
return s.ApplyToEveryValidator(validatorFunc)
}

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.SubscriberSender
OperationFeed() *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 state updates to consumers.
type Notifier interface {
StateFeed() event.SubscriberSender
StateFeed() *event.Feed
}

View File

@@ -12,10 +12,12 @@ 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",
@@ -27,13 +29,10 @@ go_test(
srcs = ["lightclient_test.go"],
deps = [
":go_default_library",
"//config/fieldparams:go_default_library",
"//consensus-types:go_default_library",
"//consensus-types/blocks:go_default_library",
"//encoding/ssz:go_default_library",
"//proto/engine/v1:go_default_library",
"//config/params:go_default_library",
"//consensus-types/primitives:go_default_library",
"//proto/eth/v2:go_default_library",
"//testing/require:go_default_library",
"//testing/util:go_default_library",
"@com_github_pkg_errors//:go_default_library",
],
)

View File

@@ -2,7 +2,6 @@ package light_client
import (
"bytes"
"context"
"fmt"
"github.com/pkg/errors"
@@ -13,19 +12,33 @@ import (
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/v5/encoding/ssz"
v11 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
enginev1 "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"
"context"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
)
const (
FinalityBranchNumOfLeaves = 6
executionBranchNumOfLeaves = 4
FinalityBranchNumOfLeaves = 6
)
func createLightClientFinalityUpdate(update *ethpbv2.LightClientUpdate) *ethpbv2.LightClientFinalityUpdate {
// 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,
FinalizedHeader: update.FinalizedHeader,
@@ -37,7 +50,15 @@ func createLightClientFinalityUpdate(update *ethpbv2.LightClientUpdate) *ethpbv2
return finalityUpdate
}
func createLightClientOptimisticUpdate(update *ethpbv2.LightClientUpdate) *ethpbv2.LightClientOptimisticUpdate {
// 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,
SyncAggregate: update.SyncAggregate,
@@ -47,44 +68,11 @@ func createLightClientOptimisticUpdate(update *ethpbv2.LightClientUpdate) *ethpb
return optimisticUpdate
}
func NewLightClientFinalityUpdateFromBeaconState(
ctx context.Context,
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, attestedBlock, finalizedBlock)
if err != nil {
return nil, err
}
return createLightClientFinalityUpdate(update), nil
}
func NewLightClientOptimisticUpdateFromBeaconState(
ctx context.Context,
state state.BeaconState,
block interfaces.ReadOnlySignedBeaconBlock,
attestedState state.BeaconState,
attestedBlock interfaces.ReadOnlySignedBeaconBlock,
) (*ethpbv2.LightClientOptimisticUpdate, error) {
update, err := NewLightClientUpdateFromBeaconState(ctx, state, block, attestedState, attestedBlock, nil)
if err != nil {
return nil, err
}
return createLightClientOptimisticUpdate(update), nil
}
func NewLightClientUpdateFromBeaconState(
ctx context.Context,
state state.BeaconState,
block interfaces.ReadOnlySignedBeaconBlock,
attestedState state.BeaconState,
attestedBlock interfaces.ReadOnlySignedBeaconBlock,
finalizedBlock interfaces.ReadOnlySignedBeaconBlock) (*ethpbv2.LightClientUpdate, error) {
attestedState state.BeaconState) (*ethpbv2.LightClientUpdate, error) {
// assert compute_epoch_at_slot(attested_state.slot) >= ALTAIR_FORK_EPOCH
attestedEpoch := slots.ToEpoch(attestedState.Slot())
if attestedEpoch < params.BeaconConfig().AltairForkEpoch {
@@ -96,6 +84,7 @@ func NewLightClientUpdateFromBeaconState(
if err != nil {
return nil, errors.Wrap(err, "could not get sync aggregate")
}
if syncAggregate.SyncCommitteeBits.Count() < params.BeaconConfig().MinSyncCommitteeParticipants {
return nil, fmt.Errorf("invalid sync committee bits count %d", syncAggregate.SyncCommitteeBits.Count())
}
@@ -112,21 +101,21 @@ func NewLightClientUpdateFromBeaconState(
return nil, errors.Wrap(err, "could not get state root")
}
header.StateRoot = stateRoot[:]
headerRoot, err := header.HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "could not get header root")
}
blockRoot, err := block.Block().HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "could not get block root")
}
if headerRoot != blockRoot {
return nil, fmt.Errorf("header root %#x not equal to block root %#x", headerRoot, blockRoot)
}
// update_signature_period = compute_sync_committee_period(compute_epoch_at_slot(block.message.slot))
updateSignaturePeriod := slots.SyncCommitteePeriod(slots.ToEpoch(block.Block().Slot()))
// assert attested_state.slot == attested_state.latest_block_header.slot
if attestedState.Slot() != attestedState.LatestBlockHeader().Slot {
return nil, fmt.Errorf("attested state slot %d not equal to attested latest block header slot %d", attestedState.Slot(), attestedState.LatestBlockHeader().Slot)
@@ -147,126 +136,303 @@ func NewLightClientUpdateFromBeaconState(
if err != nil {
return nil, errors.Wrap(err, "could not get attested header root")
}
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)
if attestedHeaderRoot != block.Block().ParentRoot() {
return nil, fmt.Errorf("attested header root %#x not equal to block parent root %#x", attestedHeaderRoot, block.Block().ParentRoot())
}
// 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()
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)
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 {
tempNextSyncCommittee, err := attestedState.NextSyncCommittee()
if err != nil {
return nil, errors.Wrap(err, "could not get next sync committee")
}
nextSyncCommittee := &ethpbv2.SyncCommittee{
Pubkeys: tempNextSyncCommittee.Pubkeys,
AggregatePubkey: tempNextSyncCommittee.AggregatePubkey,
}
nextSyncCommitteeBranch, err := attestedState.NextSyncCommitteeProof(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not get next sync committee proof")
}
// update.next_sync_committee = attested_state.next_sync_committee
result.NextSyncCommittee = nextSyncCommittee
// update.next_sync_committee_branch = NextSyncCommitteeBranch(
// compute_merkle_proof(attested_state, next_sync_committee_gindex_at_slot(attested_state.slot)))
result.NextSyncCommitteeBranch = nextSyncCommitteeBranch
}
// if finalized_block is not None
if finalizedBlock != nil && !finalizedBlock.IsNil() {
// if finalized_block.message.slot != GENESIS_SLOT
if finalizedBlock.Block().Slot() != 0 {
// update.finalized_header = block_to_light_client_header(finalized_block)
finalizedLightClientHeader, err := BlockToLightClientHeader(finalizedBlock)
if err != nil {
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)) {
return nil, fmt.Errorf("invalid finalized header root %v", attestedState.FinalizedCheckpoint().Root)
}
}
// update.finality_branch = FinalityBranch(
// compute_merkle_proof(attested_state, finalized_root_gindex_at_slot(attested_state.slot)))
finalityBranch, err := attestedState.FinalizedRootProof(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not get finalized root proof")
}
result.FinalityBranch = finalityBranch
}
// update.sync_aggregate = block.message.body.sync_aggregate
result.SyncAggregate = &ethpbv1.SyncAggregate{
syncAggregateResult := &ethpbv1.SyncAggregate{
SyncCommitteeBits: syncAggregate.SyncCommitteeBits,
SyncCommitteeSignature: syncAggregate.SyncCommitteeSignature,
}
// update.signature_slot = block.message.slot
result.SignatureSlot = block.Block().Slot()
result := &ethpbv2.LightClientUpdate{
SyncAggregate: syncAggregateResult,
SignatureSlot: block.Block().Slot(),
}
switch block.Block().Version() {
case version.Altair, version.Bellatrix:
result.AttestedHeader = &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderAltair{
HeaderAltair: &ethpbv2.LightClientHeader{
Beacon: &ethpbv1.BeaconBlockHeader{
Slot: attestedHeader.Slot,
ProposerIndex: attestedHeader.ProposerIndex,
ParentRoot: attestedHeader.ParentRoot,
StateRoot: attestedHeader.StateRoot,
BodyRoot: attestedHeader.BodyRoot,
},
},
},
}
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: &ethpbv1.BeaconBlockHeader{
Slot: attestedHeader.Slot,
ProposerIndex: attestedHeader.ProposerIndex,
ParentRoot: attestedHeader.ParentRoot,
StateRoot: attestedHeader.StateRoot,
BodyRoot: attestedHeader.BodyRoot,
},
Execution: executionPayloadHeader,
ExecutionBranch: executionPayloadProof,
},
},
}
case version.Deneb, version.Electra:
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: &ethpbv1.BeaconBlockHeader{
Slot: attestedHeader.Slot,
ProposerIndex: attestedHeader.ProposerIndex,
ParentRoot: attestedHeader.ParentRoot,
StateRoot: attestedHeader.StateRoot,
BodyRoot: attestedHeader.BodyRoot,
},
Execution: executionPayloadHeader,
ExecutionBranch: executionPayloadProof,
},
},
}
default:
return nil, fmt.Errorf("unsupported block version %s", version.String(block.Block().Version()))
}
return result, nil
}
func createDefaultLightClientUpdate() (*ethpbv2.LightClientUpdate, error) {
syncCommitteeSize := params.BeaconConfig().SyncCommitteeSize
pubKeys := make([][]byte, syncCommitteeSize)
for i := uint64(0); i < syncCommitteeSize; i++ {
pubKeys[i] = make([]byte, fieldparams.BLSPubkeyLength)
}
nextSyncCommittee := &ethpbv2.SyncCommittee{
Pubkeys: pubKeys,
AggregatePubkey: make([]byte, fieldparams.BLSPubkeyLength),
}
nextSyncCommitteeBranch := make([][]byte, fieldparams.NextSyncCommitteeBranchDepth)
for i := 0; i < fieldparams.NextSyncCommitteeBranchDepth; i++ {
nextSyncCommitteeBranch[i] = make([]byte, fieldparams.RootLength)
}
executionBranch := make([][]byte, executionBranchNumOfLeaves)
for i := 0; i < executionBranchNumOfLeaves; i++ {
executionBranch[i] = make([]byte, 32)
}
finalityBranch := make([][]byte, FinalityBranchNumOfLeaves)
for i := 0; i < FinalityBranchNumOfLeaves; i++ {
finalityBranch[i] = make([]byte, 32)
func NewLightClientFinalityUpdateFromBeaconState(
ctx context.Context,
state state.BeaconState,
block interfaces.ReadOnlySignedBeaconBlock,
attestedState state.BeaconState,
finalizedBlock interfaces.ReadOnlySignedBeaconBlock) (*ethpbv2.LightClientUpdate, error) {
result, err := NewLightClientOptimisticUpdateFromBeaconState(
ctx,
state,
block,
attestedState,
)
if err != nil {
return nil, err
}
return &ethpbv2.LightClientUpdate{
NextSyncCommittee: nextSyncCommittee,
NextSyncCommitteeBranch: nextSyncCommitteeBranch,
FinalityBranch: finalityBranch,
}, nil
// Indicate finality whenever possible
var finalizedHeaderBeacon *ethpbv1.BeaconBlockHeader
var finalityBranch [][]byte
if finalizedBlock != nil && !finalizedBlock.IsNil() {
if finalizedBlock.Block().Slot() != 0 {
tempFinalizedHeader, err := finalizedBlock.Header()
if err != nil {
return nil, errors.Wrap(err, "could not get finalized header")
}
finalizedHeaderBeacon := migration.V1Alpha1SignedHeaderToV1(tempFinalizedHeader).GetMessage()
finalizedHeaderRoot, err := finalizedHeaderBeacon.HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "could not get finalized header 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))
}
} else {
if !bytes.Equal(attestedState.FinalizedCheckpoint().Root, make([]byte, 32)) {
return nil, fmt.Errorf("invalid finalized header root %v", attestedState.FinalizedCheckpoint().Root)
}
finalizedHeaderBeacon = &ethpbv1.BeaconBlockHeader{
Slot: 0,
ProposerIndex: 0,
ParentRoot: make([]byte, 32),
StateRoot: make([]byte, 32),
BodyRoot: make([]byte, 32),
}
}
var bErr error
finalityBranch, bErr = attestedState.FinalizedRootProof(ctx)
if bErr != nil {
return nil, errors.Wrap(bErr, "could not get finalized root proof")
}
} else {
finalizedHeaderBeacon = &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)
}
}
switch block.Block().Version() {
case version.Altair, version.Bellatrix:
result.FinalizedHeader = &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderAltair{
HeaderAltair: &ethpbv2.LightClientHeader{Beacon: finalizedHeaderBeacon},
},
}
result.FinalityBranch = finalityBranch
case version.Capella:
if finalizedBlock != nil && !finalizedBlock.IsNil() {
execution, err := getExecutionPayloadHeaderCapella(finalizedBlock)
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload header")
}
executionBranch, 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: finalizedHeaderBeacon,
Execution: execution,
ExecutionBranch: executionBranch,
},
},
}
result.FinalityBranch = finalityBranch
} else {
execution := createEmptyExecutionPayloadHeaderCapella()
executionBranch := make([][]byte, 0)
result.FinalizedHeader = &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderCapella{
HeaderCapella: &ethpbv2.LightClientHeaderCapella{
Beacon: finalizedHeaderBeacon,
Execution: execution,
ExecutionBranch: executionBranch,
},
},
}
result.FinalityBranch = finalityBranch
}
case version.Deneb, version.Electra:
if finalizedBlock != nil && !finalizedBlock.IsNil() {
execution, err := getExecutionPayloadHeaderDeneb(finalizedBlock)
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload header")
}
executionBranch, 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: finalizedHeaderBeacon,
Execution: execution,
ExecutionBranch: executionBranch,
},
},
}
result.FinalityBranch = finalityBranch
} else {
execution := createEmptyExecutionPayloadHeaderDeneb()
executionBranch := make([][]byte, 0)
result.FinalizedHeader = &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderDeneb{
HeaderDeneb: &ethpbv2.LightClientHeaderDeneb{
Beacon: finalizedHeaderBeacon,
Execution: execution,
ExecutionBranch: executionBranch,
},
},
}
result.FinalityBranch = finalityBranch
}
default:
return nil, fmt.Errorf("unsupported block version %s", version.String(block.Block().Version()))
}
return result, nil
}
func ComputeTransactionsRoot(payload interfaces.ExecutionData) ([]byte, error) {
transactionsRoot, err := payload.TransactionsRoot()
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 := payload.Transactions()
transactions, err := payloadInterface.Transactions()
if err != nil {
return nil, errors.Wrap(err, "could not get transactions")
}
@@ -278,13 +444,9 @@ func ComputeTransactionsRoot(payload interfaces.ExecutionData) ([]byte, error) {
} else if err != nil {
return nil, errors.Wrap(err, "could not get transactions root")
}
return transactionsRoot, nil
}
func ComputeWithdrawalsRoot(payload interfaces.ExecutionData) ([]byte, error) {
withdrawalsRoot, err := payload.WithdrawalsRoot()
withdrawalsRoot, err := payloadInterface.WithdrawalsRoot()
if errors.Is(err, consensus_types.ErrUnsupportedField) {
withdrawals, err := payload.Withdrawals()
withdrawals, err := payloadInterface.Withdrawals()
if err != nil {
return nil, errors.Wrap(err, "could not get withdrawals")
}
@@ -296,199 +458,96 @@ func ComputeWithdrawalsRoot(payload interfaces.ExecutionData) ([]byte, error) {
} else if err != nil {
return nil, errors.Wrap(err, "could not get withdrawals root")
}
return withdrawalsRoot, nil
}
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:
denebHeader, err := blockToLightClientHeaderDeneb(context.Background(), block)
if err != nil {
return nil, errors.Wrap(err, "could not get deneb 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()))
}
parentRoot := block.Block().ParentRoot()
stateRoot := block.Block().StateRoot()
bodyRoot, err := block.Block().Body().HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "could not get body root")
}
return &ethpbv2.LightClientHeader{
Beacon: &ethpbv1.BeaconBlockHeader{
Slot: block.Block().Slot(),
ProposerIndex: block.Block().ProposerIndex(),
ParentRoot: parentRoot[:],
StateRoot: stateRoot[:],
BodyRoot: bodyRoot[:],
},
}, nil
}
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()))
}
payload, err := block.Block().Body().Execution()
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload")
}
transactionsRoot, err := ComputeTransactionsRoot(payload)
if err != nil {
return nil, err
}
withdrawalsRoot, err := ComputeWithdrawalsRoot(payload)
if err != nil {
return nil, err
}
executionHeader := &v11.ExecutionPayloadHeaderCapella{
ParentHash: payload.ParentHash(),
FeeRecipient: payload.FeeRecipient(),
StateRoot: payload.StateRoot(),
ReceiptsRoot: payload.ReceiptsRoot(),
LogsBloom: payload.LogsBloom(),
PrevRandao: payload.PrevRandao(),
BlockNumber: payload.BlockNumber(),
GasLimit: payload.GasLimit(),
GasUsed: payload.GasUsed(),
Timestamp: payload.Timestamp(),
ExtraData: payload.ExtraData(),
BaseFeePerGas: payload.BaseFeePerGas(),
BlockHash: payload.BlockHash(),
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,
}
executionPayloadProof, err := blocks.PayloadProof(ctx, block.Block())
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload proof")
}
parentRoot := block.Block().ParentRoot()
stateRoot := block.Block().StateRoot()
bodyRoot, err := block.Block().Body().HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "could not get body root")
}
return &ethpbv2.LightClientHeaderCapella{
Beacon: &ethpbv1.BeaconBlockHeader{
Slot: block.Block().Slot(),
ProposerIndex: block.Block().ProposerIndex(),
ParentRoot: parentRoot[:],
StateRoot: stateRoot[:],
BodyRoot: bodyRoot[:],
},
Execution: executionHeader,
ExecutionBranch: executionPayloadProof,
}, nil
return execution, 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 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")
}
payload, err := block.Block().Body().Execution()
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload")
}
transactionsRoot, err := ComputeTransactionsRoot(payload)
if err != nil {
return nil, err
}
withdrawalsRoot, err := ComputeWithdrawalsRoot(payload)
if err != nil {
return nil, err
}
blobGasUsed, err := payload.BlobGasUsed()
if err != nil {
return nil, errors.Wrap(err, "could not get blob gas used")
}
excessBlobGas, err := payload.ExcessBlobGas()
if err != nil {
return nil, errors.Wrap(err, "could not get excess blob gas")
}
executionHeader := &v11.ExecutionPayloadHeaderDeneb{
ParentHash: payload.ParentHash(),
FeeRecipient: payload.FeeRecipient(),
StateRoot: payload.StateRoot(),
ReceiptsRoot: payload.ReceiptsRoot(),
LogsBloom: payload.LogsBloom(),
PrevRandao: payload.PrevRandao(),
BlockNumber: payload.BlockNumber(),
GasLimit: payload.GasLimit(),
GasUsed: payload.GasUsed(),
Timestamp: payload.Timestamp(),
ExtraData: payload.ExtraData(),
BaseFeePerGas: payload.BaseFeePerGas(),
BlockHash: payload.BlockHash(),
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,
BlobGasUsed: blobGasUsed,
ExcessBlobGas: excessBlobGas,
}
executionPayloadProof, err := blocks.PayloadProof(ctx, block.Block())
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload proof")
}
parentRoot := block.Block().ParentRoot()
stateRoot := block.Block().StateRoot()
bodyRoot, err := block.Block().Body().HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "could not get body root")
}
return &ethpbv2.LightClientHeaderDeneb{
Beacon: &ethpbv1.BeaconBlockHeader{
Slot: block.Block().Slot(),
ProposerIndex: block.Block().ProposerIndex(),
ParentRoot: parentRoot[:],
StateRoot: stateRoot[:],
BodyRoot: bodyRoot[:],
},
Execution: executionHeader,
ExecutionBranch: executionPayloadProof,
}, nil
return execution, nil
}
func NewLightClientUpdateFromFinalityUpdate(update *ethpbv2.LightClientFinalityUpdate) *ethpbv2.LightClientUpdate {
return &ethpbv2.LightClientUpdate{
AttestedHeader: update.AttestedHeader,
FinalizedHeader: update.FinalizedHeader,
FinalityBranch: update.FinalityBranch,
SyncAggregate: update.SyncAggregate,
SignatureSlot: update.SignatureSlot,
}
}
func NewLightClientUpdateFromOptimisticUpdate(update *ethpbv2.LightClientOptimisticUpdate) *ethpbv2.LightClientUpdate {
return &ethpbv2.LightClientUpdate{
AttestedHeader: update.AttestedHeader,
SyncAggregate: update.SyncAggregate,
SignatureSlot: update.SignatureSlot,
}
}

View File

@@ -3,600 +3,140 @@ package light_client_test
import (
"testing"
"github.com/pkg/errors"
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/encoding/ssz"
v11 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
lightClient "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/light-client"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
v2 "github.com/prysmaticlabs/prysm/v5/proto/eth/v2"
"github.com/prysmaticlabs/prysm/v5/testing/require"
"github.com/prysmaticlabs/prysm/v5/testing/util"
)
func TestLightClient_NewLightClientOptimisticUpdateFromBeaconState(t *testing.T) {
t.Run("Altair", func(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestAltair()
func TestLightClient_NewLightClientOptimisticUpdateFromBeaconStateCapella(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestCapella()
update, err := lightClient.NewLightClientOptimisticUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState, l.AttestedBlock)
require.NoError(t, err)
require.NotNil(t, update, "update is nil")
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot, "Signature slot is not equal")
update, err := lightClient.NewLightClientOptimisticUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState)
require.NoError(t, err)
require.NotNil(t, update, "update is nil")
l.CheckSyncAggregate(update.SyncAggregate)
l.CheckAttestedHeader(update.AttestedHeader)
})
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot, "Signature slot is not equal")
t.Run("Capella", func(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestCapella(false)
l.CheckSyncAggregate(update)
l.CheckAttestedHeader(update)
update, err := lightClient.NewLightClientOptimisticUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState, l.AttestedBlock)
require.NoError(t, err)
require.NotNil(t, update, "update is nil")
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot, "Signature slot is not equal")
l.CheckSyncAggregate(update.SyncAggregate)
l.CheckAttestedHeader(update.AttestedHeader)
})
t.Run("Deneb", func(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestDeneb(false)
update, err := lightClient.NewLightClientOptimisticUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState, l.AttestedBlock)
require.NoError(t, err)
require.NotNil(t, update, "update is nil")
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot, "Signature slot is not equal")
l.CheckSyncAggregate(update.SyncAggregate)
l.CheckAttestedHeader(update.AttestedHeader)
})
require.Equal(t, (*v2.LightClientHeaderContainer)(nil), update.FinalizedHeader, "Finalized header is not nil")
require.DeepSSZEqual(t, ([][]byte)(nil), update.FinalityBranch, "Finality branch is not nil")
}
func TestLightClient_NewLightClientFinalityUpdateFromBeaconState(t *testing.T) {
t.Run("Altair", func(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestAltair()
func TestLightClient_NewLightClientOptimisticUpdateFromBeaconStateAltair(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestAltair()
t.Run("FinalizedBlock Not Nil", func(t *testing.T) {
update, err := lightClient.NewLightClientFinalityUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState, l.AttestedBlock, l.FinalizedBlock)
require.NoError(t, err)
require.NotNil(t, update, "update is nil")
update, err := lightClient.NewLightClientOptimisticUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState)
require.NoError(t, err)
require.NotNil(t, update, "update is nil")
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot, "Signature slot is not equal")
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot, "Signature slot is not equal")
l.CheckSyncAggregate(update.SyncAggregate)
l.CheckAttestedHeader(update.AttestedHeader)
l.CheckSyncAggregate(update)
l.CheckAttestedHeader(update)
finalizedBlockHeader, err := l.FinalizedBlock.Header()
require.NoError(t, err)
//zeroHash := params.BeaconConfig().ZeroHash[:]
require.NotNil(t, update.FinalizedHeader, "Finalized header is nil")
updateFinalizedHeaderBeacon, err := update.FinalizedHeader.GetBeacon()
require.NoError(t, err)
require.Equal(t, finalizedBlockHeader.Header.Slot, updateFinalizedHeaderBeacon.Slot, "Finalized header slot is not equal")
require.Equal(t, finalizedBlockHeader.Header.ProposerIndex, updateFinalizedHeaderBeacon.ProposerIndex, "Finalized header proposer index is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.ParentRoot, updateFinalizedHeaderBeacon.ParentRoot, "Finalized header parent root is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.StateRoot, updateFinalizedHeaderBeacon.StateRoot, "Finalized header state root is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.BodyRoot, updateFinalizedHeaderBeacon.BodyRoot, "Finalized header body root is not equal")
require.Equal(t, lightClient.FinalityBranchNumOfLeaves, len(update.FinalityBranch), "Invalid finality branch leaves")
finalityBranch, err := l.AttestedState.FinalizedRootProof(l.Ctx)
require.NoError(t, err)
for i, leaf := range update.FinalityBranch {
require.DeepSSZEqual(t, finalityBranch[i], leaf, "Leaf is not equal")
}
})
})
t.Run("Capella", func(t *testing.T) {
t.Run("FinalizedBlock Not Nil", func(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestCapella(false)
update, err := lightClient.NewLightClientFinalityUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState, l.AttestedBlock, l.FinalizedBlock)
require.NoError(t, err)
require.NotNil(t, update, "update is nil")
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot, "Signature slot is not equal")
l.CheckSyncAggregate(update.SyncAggregate)
l.CheckAttestedHeader(update.AttestedHeader)
finalizedBlockHeader, err := l.FinalizedBlock.Header()
require.NoError(t, err)
require.NotNil(t, update.FinalizedHeader, "Finalized header is nil")
updateFinalizedHeaderBeacon, err := update.FinalizedHeader.GetBeacon()
require.NoError(t, err)
require.Equal(t, finalizedBlockHeader.Header.Slot, updateFinalizedHeaderBeacon.Slot, "Finalized header slot is not equal")
require.Equal(t, finalizedBlockHeader.Header.ProposerIndex, updateFinalizedHeaderBeacon.ProposerIndex, "Finalized header proposer index is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.ParentRoot, updateFinalizedHeaderBeacon.ParentRoot, "Finalized header parent root is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.StateRoot, updateFinalizedHeaderBeacon.StateRoot, "Finalized header state root is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.BodyRoot, updateFinalizedHeaderBeacon.BodyRoot, "Finalized header body root is not equal")
require.Equal(t, lightClient.FinalityBranchNumOfLeaves, len(update.FinalityBranch), "Invalid finality branch leaves")
finalityBranch, err := l.AttestedState.FinalizedRootProof(l.Ctx)
require.NoError(t, err)
for i, leaf := range update.FinalityBranch {
require.DeepSSZEqual(t, finalityBranch[i], leaf, "Leaf is not equal")
}
// Check Execution BlockHash
payloadInterface, err := l.FinalizedBlock.Block().Body().Execution()
require.NoError(t, err)
transactionsRoot, err := payloadInterface.TransactionsRoot()
if errors.Is(err, consensustypes.ErrUnsupportedField) {
transactions, err := payloadInterface.Transactions()
require.NoError(t, err)
transactionsRootArray, err := ssz.TransactionsRoot(transactions)
require.NoError(t, err)
transactionsRoot = transactionsRootArray[:]
} else {
require.NoError(t, err)
}
withdrawalsRoot, err := payloadInterface.WithdrawalsRoot()
if errors.Is(err, consensustypes.ErrUnsupportedField) {
withdrawals, err := payloadInterface.Withdrawals()
require.NoError(t, err)
withdrawalsRootArray, err := ssz.WithdrawalSliceRoot(withdrawals, fieldparams.MaxWithdrawalsPerPayload)
require.NoError(t, err)
withdrawalsRoot = withdrawalsRootArray[:]
} else {
require.NoError(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,
}
require.DeepSSZEqual(t, execution, update.FinalizedHeader.GetHeaderCapella().Execution, "Finalized Block Execution is not equal")
})
t.Run("FinalizedBlock In Previous Fork", func(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestCapellaFinalizedBlockAltair(false)
update, err := lightClient.NewLightClientFinalityUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState, l.AttestedBlock, l.FinalizedBlock)
require.NoError(t, err)
require.NotNil(t, update, "update is nil")
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot, "Signature slot is not equal")
l.CheckSyncAggregate(update.SyncAggregate)
l.CheckAttestedHeader(update.AttestedHeader)
finalizedBlockHeader, err := l.FinalizedBlock.Header()
require.NoError(t, err)
require.NotNil(t, update.FinalizedHeader, "Finalized header is nil")
updateFinalizedHeaderBeacon, err := update.FinalizedHeader.GetBeacon()
require.NoError(t, err)
require.Equal(t, finalizedBlockHeader.Header.Slot, updateFinalizedHeaderBeacon.Slot, "Finalized header slot is not equal")
require.Equal(t, finalizedBlockHeader.Header.ProposerIndex, updateFinalizedHeaderBeacon.ProposerIndex, "Finalized header proposer index is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.ParentRoot, updateFinalizedHeaderBeacon.ParentRoot, "Finalized header parent root is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.StateRoot, updateFinalizedHeaderBeacon.StateRoot, "Finalized header state root is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.BodyRoot, updateFinalizedHeaderBeacon.BodyRoot, "Finalized header body root is not equal")
require.Equal(t, lightClient.FinalityBranchNumOfLeaves, len(update.FinalityBranch), "Invalid finality branch leaves")
finalityBranch, err := l.AttestedState.FinalizedRootProof(l.Ctx)
require.NoError(t, err)
for i, leaf := range update.FinalityBranch {
require.DeepSSZEqual(t, finalityBranch[i], leaf, "Leaf is not equal")
}
})
})
t.Run("Deneb", func(t *testing.T) {
t.Run("FinalizedBlock Not Nil", func(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestDeneb(false)
update, err := lightClient.NewLightClientFinalityUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState, l.AttestedBlock, l.FinalizedBlock)
require.NoError(t, err)
require.NotNil(t, update, "update is nil")
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot, "Signature slot is not equal")
l.CheckSyncAggregate(update.SyncAggregate)
l.CheckAttestedHeader(update.AttestedHeader)
//zeroHash := params.BeaconConfig().ZeroHash[:]
finalizedBlockHeader, err := l.FinalizedBlock.Header()
require.NoError(t, err)
require.NotNil(t, update.FinalizedHeader, "Finalized header is nil")
updateFinalizedHeaderBeacon, err := update.FinalizedHeader.GetBeacon()
require.NoError(t, err)
require.Equal(t, finalizedBlockHeader.Header.Slot, updateFinalizedHeaderBeacon.Slot, "Finalized header slot is not equal")
require.Equal(t, finalizedBlockHeader.Header.ProposerIndex, updateFinalizedHeaderBeacon.ProposerIndex, "Finalized header proposer index is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.ParentRoot, updateFinalizedHeaderBeacon.ParentRoot, "Finalized header parent root is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.StateRoot, updateFinalizedHeaderBeacon.StateRoot, "Finalized header state root is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.BodyRoot, updateFinalizedHeaderBeacon.BodyRoot, "Finalized header body root is not equal")
require.Equal(t, lightClient.FinalityBranchNumOfLeaves, len(update.FinalityBranch), "Invalid finality branch leaves")
finalityBranch, err := l.AttestedState.FinalizedRootProof(l.Ctx)
require.NoError(t, err)
for i, leaf := range update.FinalityBranch {
require.DeepSSZEqual(t, finalityBranch[i], leaf, "Leaf is not equal")
}
// Check Execution BlockHash
payloadInterface, err := l.FinalizedBlock.Block().Body().Execution()
require.NoError(t, err)
transactionsRoot, err := payloadInterface.TransactionsRoot()
if errors.Is(err, consensustypes.ErrUnsupportedField) {
transactions, err := payloadInterface.Transactions()
require.NoError(t, err)
transactionsRootArray, err := ssz.TransactionsRoot(transactions)
require.NoError(t, err)
transactionsRoot = transactionsRootArray[:]
} else {
require.NoError(t, err)
}
withdrawalsRoot, err := payloadInterface.WithdrawalsRoot()
if errors.Is(err, consensustypes.ErrUnsupportedField) {
withdrawals, err := payloadInterface.Withdrawals()
require.NoError(t, err)
withdrawalsRootArray, err := ssz.WithdrawalSliceRoot(withdrawals, fieldparams.MaxWithdrawalsPerPayload)
require.NoError(t, err)
withdrawalsRoot = withdrawalsRootArray[:]
} else {
require.NoError(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,
}
require.DeepSSZEqual(t, execution, update.FinalizedHeader.GetHeaderDeneb().Execution, "Finalized Block Execution is not equal")
})
t.Run("FinalizedBlock In Previous Fork", func(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestDenebFinalizedBlockCapella(false)
update, err := lightClient.NewLightClientFinalityUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState, l.AttestedBlock, l.FinalizedBlock)
require.NoError(t, err)
require.NotNil(t, update, "update is nil")
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot, "Signature slot is not equal")
l.CheckSyncAggregate(update.SyncAggregate)
l.CheckAttestedHeader(update.AttestedHeader)
finalizedBlockHeader, err := l.FinalizedBlock.Header()
require.NoError(t, err)
require.NotNil(t, update.FinalizedHeader, "Finalized header is nil")
updateFinalizedHeaderBeacon, err := update.FinalizedHeader.GetBeacon()
require.NoError(t, err)
require.Equal(t, finalizedBlockHeader.Header.Slot, updateFinalizedHeaderBeacon.Slot, "Finalized header slot is not equal")
require.Equal(t, finalizedBlockHeader.Header.ProposerIndex, updateFinalizedHeaderBeacon.ProposerIndex, "Finalized header proposer index is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.ParentRoot, updateFinalizedHeaderBeacon.ParentRoot, "Finalized header parent root is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.StateRoot, updateFinalizedHeaderBeacon.StateRoot, "Finalized header state root is not equal")
require.DeepSSZEqual(t, finalizedBlockHeader.Header.BodyRoot, updateFinalizedHeaderBeacon.BodyRoot, "Finalized header body root is not equal")
require.Equal(t, lightClient.FinalityBranchNumOfLeaves, len(update.FinalityBranch), "Invalid finality branch leaves")
finalityBranch, err := l.AttestedState.FinalizedRootProof(l.Ctx)
require.NoError(t, err)
for i, leaf := range update.FinalityBranch {
require.DeepSSZEqual(t, finalityBranch[i], leaf, "Leaf is not equal")
}
// Check Execution BlockHash
payloadInterface, err := l.FinalizedBlock.Block().Body().Execution()
require.NoError(t, err)
transactionsRoot, err := payloadInterface.TransactionsRoot()
if errors.Is(err, consensustypes.ErrUnsupportedField) {
transactions, err := payloadInterface.Transactions()
require.NoError(t, err)
transactionsRootArray, err := ssz.TransactionsRoot(transactions)
require.NoError(t, err)
transactionsRoot = transactionsRootArray[:]
} else {
require.NoError(t, err)
}
withdrawalsRoot, err := payloadInterface.WithdrawalsRoot()
if errors.Is(err, consensustypes.ErrUnsupportedField) {
withdrawals, err := payloadInterface.Withdrawals()
require.NoError(t, err)
withdrawalsRootArray, err := ssz.WithdrawalSliceRoot(withdrawals, fieldparams.MaxWithdrawalsPerPayload)
require.NoError(t, err)
withdrawalsRoot = withdrawalsRootArray[:]
} else {
require.NoError(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,
}
require.DeepSSZEqual(t, execution, update.FinalizedHeader.GetHeaderCapella().Execution, "Finalized Block Execution is not equal")
})
})
require.Equal(t, (*v2.LightClientHeaderContainer)(nil), update.FinalizedHeader, "Finalized header is not nil")
require.DeepSSZEqual(t, ([][]byte)(nil), update.FinalityBranch, "Finality branch is not nil")
}
func TestLightClient_BlockToLightClientHeader(t *testing.T) {
t.Run("Altair", func(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestAltair()
func TestLightClient_NewLightClientOptimisticUpdateFromBeaconStateDeneb(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestDeneb()
container, err := lightClient.BlockToLightClientHeader(l.Block)
require.NoError(t, err)
header := container.GetHeaderAltair()
require.NotNil(t, header, "header is nil")
update, err := lightClient.NewLightClientOptimisticUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState)
require.NoError(t, err)
require.NotNil(t, update, "update is nil")
parentRoot := l.Block.Block().ParentRoot()
stateRoot := l.Block.Block().StateRoot()
bodyRoot, err := l.Block.Block().Body().HashTreeRoot()
require.NoError(t, err)
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot, "Signature slot is not equal")
require.Equal(t, l.Block.Block().Slot(), header.Beacon.Slot, "Slot is not equal")
require.Equal(t, l.Block.Block().ProposerIndex(), header.Beacon.ProposerIndex, "Proposer index is not equal")
require.DeepSSZEqual(t, parentRoot[:], header.Beacon.ParentRoot, "Parent root is not equal")
require.DeepSSZEqual(t, stateRoot[:], header.Beacon.StateRoot, "State root is not equal")
require.DeepSSZEqual(t, bodyRoot[:], header.Beacon.BodyRoot, "Body root is not equal")
})
l.CheckSyncAggregate(update)
l.CheckAttestedHeader(update)
t.Run("Capella", func(t *testing.T) {
t.Run("Non-Blinded Beacon Block", func(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestCapella(false)
container, err := lightClient.BlockToLightClientHeader(l.Block)
require.NoError(t, err)
header := container.GetHeaderCapella()
require.NotNil(t, header, "header is nil")
parentRoot := l.Block.Block().ParentRoot()
stateRoot := l.Block.Block().StateRoot()
bodyRoot, err := l.Block.Block().Body().HashTreeRoot()
require.NoError(t, err)
payload, err := l.Block.Block().Body().Execution()
require.NoError(t, err)
transactionsRoot, err := lightClient.ComputeTransactionsRoot(payload)
require.NoError(t, err)
withdrawalsRoot, err := lightClient.ComputeWithdrawalsRoot(payload)
require.NoError(t, err)
executionHeader := &v11.ExecutionPayloadHeaderCapella{
ParentHash: payload.ParentHash(),
FeeRecipient: payload.FeeRecipient(),
StateRoot: payload.StateRoot(),
ReceiptsRoot: payload.ReceiptsRoot(),
LogsBloom: payload.LogsBloom(),
PrevRandao: payload.PrevRandao(),
BlockNumber: payload.BlockNumber(),
GasLimit: payload.GasLimit(),
GasUsed: payload.GasUsed(),
Timestamp: payload.Timestamp(),
ExtraData: payload.ExtraData(),
BaseFeePerGas: payload.BaseFeePerGas(),
BlockHash: payload.BlockHash(),
TransactionsRoot: transactionsRoot,
WithdrawalsRoot: withdrawalsRoot,
}
executionPayloadProof, err := blocks.PayloadProof(l.Ctx, l.Block.Block())
require.NoError(t, err)
require.Equal(t, l.Block.Block().Slot(), header.Beacon.Slot, "Slot is not equal")
require.Equal(t, l.Block.Block().ProposerIndex(), header.Beacon.ProposerIndex, "Proposer index is not equal")
require.DeepSSZEqual(t, parentRoot[:], header.Beacon.ParentRoot, "Parent root is not equal")
require.DeepSSZEqual(t, stateRoot[:], header.Beacon.StateRoot, "State root is not equal")
require.DeepSSZEqual(t, bodyRoot[:], header.Beacon.BodyRoot, "Body root is not equal")
require.DeepSSZEqual(t, executionHeader, header.Execution, "Execution headers are not equal")
require.DeepSSZEqual(t, executionPayloadProof, header.ExecutionBranch, "Execution payload proofs are not equal")
})
t.Run("Blinded Beacon Block", func(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestCapella(true)
container, err := lightClient.BlockToLightClientHeader(l.Block)
require.NoError(t, err)
header := container.GetHeaderCapella()
require.NotNil(t, header, "header is nil")
parentRoot := l.Block.Block().ParentRoot()
stateRoot := l.Block.Block().StateRoot()
bodyRoot, err := l.Block.Block().Body().HashTreeRoot()
require.NoError(t, err)
payload, err := l.Block.Block().Body().Execution()
require.NoError(t, err)
transactionsRoot, err := payload.TransactionsRoot()
require.NoError(t, err)
withdrawalsRoot, err := payload.WithdrawalsRoot()
require.NoError(t, err)
executionHeader := &v11.ExecutionPayloadHeaderCapella{
ParentHash: payload.ParentHash(),
FeeRecipient: payload.FeeRecipient(),
StateRoot: payload.StateRoot(),
ReceiptsRoot: payload.ReceiptsRoot(),
LogsBloom: payload.LogsBloom(),
PrevRandao: payload.PrevRandao(),
BlockNumber: payload.BlockNumber(),
GasLimit: payload.GasLimit(),
GasUsed: payload.GasUsed(),
Timestamp: payload.Timestamp(),
ExtraData: payload.ExtraData(),
BaseFeePerGas: payload.BaseFeePerGas(),
BlockHash: payload.BlockHash(),
TransactionsRoot: transactionsRoot,
WithdrawalsRoot: withdrawalsRoot,
}
executionPayloadProof, err := blocks.PayloadProof(l.Ctx, l.Block.Block())
require.NoError(t, err)
require.Equal(t, l.Block.Block().Slot(), header.Beacon.Slot, "Slot is not equal")
require.Equal(t, l.Block.Block().ProposerIndex(), header.Beacon.ProposerIndex, "Proposer index is not equal")
require.DeepSSZEqual(t, parentRoot[:], header.Beacon.ParentRoot, "Parent root is not equal")
require.DeepSSZEqual(t, stateRoot[:], header.Beacon.StateRoot, "State root is not equal")
require.DeepSSZEqual(t, bodyRoot[:], header.Beacon.BodyRoot, "Body root is not equal")
require.DeepSSZEqual(t, executionHeader, header.Execution, "Execution headers are not equal")
require.DeepSSZEqual(t, executionPayloadProof, header.ExecutionBranch, "Execution payload proofs are not equal")
})
})
t.Run("Deneb", func(t *testing.T) {
t.Run("Non-Blinded Beacon Block", func(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestDeneb(false)
container, err := lightClient.BlockToLightClientHeader(l.Block)
require.NoError(t, err)
header := container.GetHeaderDeneb()
require.NotNil(t, header, "header is nil")
parentRoot := l.Block.Block().ParentRoot()
stateRoot := l.Block.Block().StateRoot()
bodyRoot, err := l.Block.Block().Body().HashTreeRoot()
require.NoError(t, err)
payload, err := l.Block.Block().Body().Execution()
require.NoError(t, err)
transactionsRoot, err := lightClient.ComputeTransactionsRoot(payload)
require.NoError(t, err)
withdrawalsRoot, err := lightClient.ComputeWithdrawalsRoot(payload)
require.NoError(t, err)
blobGasUsed, err := payload.BlobGasUsed()
require.NoError(t, err)
excessBlobGas, err := payload.ExcessBlobGas()
require.NoError(t, err)
executionHeader := &v11.ExecutionPayloadHeaderDeneb{
ParentHash: payload.ParentHash(),
FeeRecipient: payload.FeeRecipient(),
StateRoot: payload.StateRoot(),
ReceiptsRoot: payload.ReceiptsRoot(),
LogsBloom: payload.LogsBloom(),
PrevRandao: payload.PrevRandao(),
BlockNumber: payload.BlockNumber(),
GasLimit: payload.GasLimit(),
GasUsed: payload.GasUsed(),
Timestamp: payload.Timestamp(),
ExtraData: payload.ExtraData(),
BaseFeePerGas: payload.BaseFeePerGas(),
BlockHash: payload.BlockHash(),
TransactionsRoot: transactionsRoot,
WithdrawalsRoot: withdrawalsRoot,
BlobGasUsed: blobGasUsed,
ExcessBlobGas: excessBlobGas,
}
executionPayloadProof, err := blocks.PayloadProof(l.Ctx, l.Block.Block())
require.NoError(t, err)
require.Equal(t, l.Block.Block().Slot(), header.Beacon.Slot, "Slot is not equal")
require.Equal(t, l.Block.Block().ProposerIndex(), header.Beacon.ProposerIndex, "Proposer index is not equal")
require.DeepSSZEqual(t, parentRoot[:], header.Beacon.ParentRoot, "Parent root is not equal")
require.DeepSSZEqual(t, stateRoot[:], header.Beacon.StateRoot, "State root is not equal")
require.DeepSSZEqual(t, bodyRoot[:], header.Beacon.BodyRoot, "Body root is not equal")
require.DeepSSZEqual(t, executionHeader, header.Execution, "Execution headers are not equal")
require.DeepSSZEqual(t, executionPayloadProof, header.ExecutionBranch, "Execution payload proofs are not equal")
})
t.Run("Blinded Beacon Block", func(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestDeneb(true)
container, err := lightClient.BlockToLightClientHeader(l.Block)
require.NoError(t, err)
header := container.GetHeaderDeneb()
require.NotNil(t, header, "header is nil")
parentRoot := l.Block.Block().ParentRoot()
stateRoot := l.Block.Block().StateRoot()
bodyRoot, err := l.Block.Block().Body().HashTreeRoot()
require.NoError(t, err)
payload, err := l.Block.Block().Body().Execution()
require.NoError(t, err)
transactionsRoot, err := payload.TransactionsRoot()
require.NoError(t, err)
withdrawalsRoot, err := payload.WithdrawalsRoot()
require.NoError(t, err)
blobGasUsed, err := payload.BlobGasUsed()
require.NoError(t, err)
excessBlobGas, err := payload.ExcessBlobGas()
require.NoError(t, err)
executionHeader := &v11.ExecutionPayloadHeaderDeneb{
ParentHash: payload.ParentHash(),
FeeRecipient: payload.FeeRecipient(),
StateRoot: payload.StateRoot(),
ReceiptsRoot: payload.ReceiptsRoot(),
LogsBloom: payload.LogsBloom(),
PrevRandao: payload.PrevRandao(),
BlockNumber: payload.BlockNumber(),
GasLimit: payload.GasLimit(),
GasUsed: payload.GasUsed(),
Timestamp: payload.Timestamp(),
ExtraData: payload.ExtraData(),
BaseFeePerGas: payload.BaseFeePerGas(),
BlockHash: payload.BlockHash(),
TransactionsRoot: transactionsRoot,
WithdrawalsRoot: withdrawalsRoot,
BlobGasUsed: blobGasUsed,
ExcessBlobGas: excessBlobGas,
}
executionPayloadProof, err := blocks.PayloadProof(l.Ctx, l.Block.Block())
require.NoError(t, err)
require.Equal(t, l.Block.Block().Slot(), header.Beacon.Slot, "Slot is not equal")
require.Equal(t, l.Block.Block().ProposerIndex(), header.Beacon.ProposerIndex, "Proposer index is not equal")
require.DeepSSZEqual(t, parentRoot[:], header.Beacon.ParentRoot, "Parent root is not equal")
require.DeepSSZEqual(t, stateRoot[:], header.Beacon.StateRoot, "State root is not equal")
require.DeepSSZEqual(t, bodyRoot[:], header.Beacon.BodyRoot, "Body root is not equal")
require.DeepSSZEqual(t, executionHeader, header.Execution, "Execution headers are not equal")
require.DeepSSZEqual(t, executionPayloadProof, header.ExecutionBranch, "Execution payload proofs are not equal")
})
})
require.Equal(t, (*v2.LightClientHeaderContainer)(nil), update.FinalizedHeader, "Finalized header is not nil")
require.DeepSSZEqual(t, ([][]byte)(nil), update.FinalityBranch, "Finality branch is not nil")
}
func TestLightClient_NewLightClientFinalityUpdateFromBeaconStateCapella(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestCapella()
update, err := lightClient.NewLightClientFinalityUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState, nil)
require.NoError(t, err)
require.NotNil(t, update, "update is nil")
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot, "Signature slot is not equal")
l.CheckSyncAggregate(update)
l.CheckAttestedHeader(update)
zeroHash := params.BeaconConfig().ZeroHash[:]
require.NotNil(t, update.FinalizedHeader, "Finalized header is nil")
updateFinalizedHeaderBeacon, err := update.FinalizedHeader.GetBeacon()
require.NoError(t, err)
require.Equal(t, primitives.Slot(0), updateFinalizedHeaderBeacon.Slot, "Finalized header slot is not zero")
require.Equal(t, primitives.ValidatorIndex(0), updateFinalizedHeaderBeacon.ProposerIndex, "Finalized header proposer index is not zero")
require.DeepSSZEqual(t, zeroHash, updateFinalizedHeaderBeacon.ParentRoot, "Finalized header parent root is not zero")
require.DeepSSZEqual(t, zeroHash, updateFinalizedHeaderBeacon.StateRoot, "Finalized header state root is not zero")
require.DeepSSZEqual(t, zeroHash, updateFinalizedHeaderBeacon.BodyRoot, "Finalized header body root is not zero")
require.Equal(t, lightClient.FinalityBranchNumOfLeaves, len(update.FinalityBranch), "Invalid finality branch leaves")
for _, leaf := range update.FinalityBranch {
require.DeepSSZEqual(t, zeroHash, leaf, "Leaf is not zero")
}
}
func TestLightClient_NewLightClientFinalityUpdateFromBeaconStateAltair(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestAltair()
update, err := lightClient.NewLightClientFinalityUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState, nil)
require.NoError(t, err)
require.NotNil(t, update, "update is nil")
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot, "Signature slot is not equal")
l.CheckSyncAggregate(update)
l.CheckAttestedHeader(update)
zeroHash := params.BeaconConfig().ZeroHash[:]
require.NotNil(t, update.FinalizedHeader, "Finalized header is nil")
updateFinalizedHeaderBeacon, err := update.FinalizedHeader.GetBeacon()
require.NoError(t, err)
require.Equal(t, primitives.Slot(0), updateFinalizedHeaderBeacon.Slot, "Finalized header slot is not zero")
require.Equal(t, primitives.ValidatorIndex(0), updateFinalizedHeaderBeacon.ProposerIndex, "Finalized header proposer index is not zero")
require.DeepSSZEqual(t, zeroHash, updateFinalizedHeaderBeacon.ParentRoot, "Finalized header parent root is not zero")
require.DeepSSZEqual(t, zeroHash, updateFinalizedHeaderBeacon.StateRoot, "Finalized header state root is not zero")
require.DeepSSZEqual(t, zeroHash, updateFinalizedHeaderBeacon.BodyRoot, "Finalized header body root is not zero")
require.Equal(t, lightClient.FinalityBranchNumOfLeaves, len(update.FinalityBranch), "Invalid finality branch leaves")
for _, leaf := range update.FinalityBranch {
require.DeepSSZEqual(t, zeroHash, leaf, "Leaf is not zero")
}
}
func TestLightClient_NewLightClientFinalityUpdateFromBeaconStateDeneb(t *testing.T) {
l := util.NewTestLightClient(t).SetupTestDeneb()
update, err := lightClient.NewLightClientFinalityUpdateFromBeaconState(l.Ctx, l.State, l.Block, l.AttestedState, nil)
require.NoError(t, err)
require.NotNil(t, update, "update is nil")
require.Equal(t, l.Block.Block().Slot(), update.SignatureSlot, "Signature slot is not equal")
l.CheckSyncAggregate(update)
l.CheckAttestedHeader(update)
zeroHash := params.BeaconConfig().ZeroHash[:]
require.NotNil(t, update.FinalizedHeader, "Finalized header is nil")
updateFinalizedHeaderBeacon, err := update.FinalizedHeader.GetBeacon()
require.NoError(t, err)
require.Equal(t, primitives.Slot(0), updateFinalizedHeaderBeacon.Slot, "Finalized header slot is not zero")
require.Equal(t, primitives.ValidatorIndex(0), updateFinalizedHeaderBeacon.ProposerIndex, "Finalized header proposer index is not zero")
require.DeepSSZEqual(t, zeroHash, updateFinalizedHeaderBeacon.ParentRoot, "Finalized header parent root is not zero")
require.DeepSSZEqual(t, zeroHash, updateFinalizedHeaderBeacon.StateRoot, "Finalized header state root is not zero")
require.DeepSSZEqual(t, zeroHash, updateFinalizedHeaderBeacon.BodyRoot, "Finalized header body root is not zero")
require.DeepSSZEqual(t, zeroHash, update.FinalizedHeader.GetHeaderDeneb().Execution.BlockHash, "Execution BlockHash is not zero")
require.Equal(t, lightClient.FinalityBranchNumOfLeaves, len(update.FinalityBranch), "Invalid finality branch leaves")
for _, leaf := range update.FinalityBranch {
require.DeepSSZEqual(t, zeroHash, leaf, "Leaf is not zero")
}
}
// TODO - add finality update tests with non-nil finalized block for different versions

View File

@@ -49,7 +49,7 @@ go_library(
"@com_github_prometheus_client_golang//prometheus:go_default_library",
"@com_github_prometheus_client_golang//prometheus/promauto:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@io_opentelemetry_go_otel_trace//:go_default_library",
"@io_opencensus_go//trace:go_default_library",
],
)

View File

@@ -25,9 +25,9 @@ import (
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing"
prysmTrace "github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"go.opentelemetry.io/otel/trace"
goTrace "go.opencensus.io/trace"
)
type customProcessingFn func(context.Context, state.BeaconState) error
@@ -63,7 +63,7 @@ func ExecuteStateTransition(
return nil, err
}
ctx, span := prysmTrace.StartSpan(ctx, "core.state.ExecuteStateTransition")
ctx, span := trace.StartSpan(ctx, "core.state.ExecuteStateTransition")
defer span.End()
var err error
@@ -103,9 +103,9 @@ func ExecuteStateTransition(
// previous_block_root = hash_tree_root(state.latest_block_header)
// state.block_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_block_root
func ProcessSlot(ctx context.Context, state state.BeaconState) (state.BeaconState, error) {
ctx, span := prysmTrace.StartSpan(ctx, "core.state.ProcessSlot")
ctx, span := trace.StartSpan(ctx, "core.state.ProcessSlot")
defer span.End()
span.SetAttributes(prysmTrace.Int64Attribute("slot", int64(state.Slot()))) // lint:ignore uintcast -- This is OK for tracing.
span.AddAttributes(trace.Int64Attribute("slot", int64(state.Slot()))) // lint:ignore uintcast -- This is OK for tracing.
prevStateRoot, err := state.HashTreeRoot(ctx)
if err != nil {
@@ -148,7 +148,7 @@ func ProcessSlotsUsingNextSlotCache(
parentState state.BeaconState,
parentRoot []byte,
slot primitives.Slot) (state.BeaconState, error) {
ctx, span := prysmTrace.StartSpan(ctx, "core.state.ProcessSlotsUsingNextSlotCache")
ctx, span := trace.StartSpan(ctx, "core.state.ProcessSlotsUsingNextSlotCache")
defer span.End()
nextSlotState := NextSlotState(parentRoot, slot)
@@ -178,12 +178,12 @@ func ProcessSlotsIfPossible(ctx context.Context, state state.BeaconState, target
// ProcessSlots includes core slot processing as well as a cache
func ProcessSlots(ctx context.Context, state state.BeaconState, slot primitives.Slot) (state.BeaconState, error) {
ctx, span := prysmTrace.StartSpan(ctx, "core.state.ProcessSlots")
ctx, span := trace.StartSpan(ctx, "core.state.ProcessSlots")
defer span.End()
if state == nil || state.IsNil() {
return nil, errors.New("nil state")
}
span.SetAttributes(prysmTrace.Int64Attribute("slots", int64(slot)-int64(state.Slot()))) // lint:ignore uintcast -- This is OK for tracing.
span.AddAttributes(trace.Int64Attribute("slots", int64(slot)-int64(state.Slot()))) // lint:ignore uintcast -- This is OK for tracing.
// The block must have a higher slot than parent state.
if state.Slot() >= slot {
@@ -259,7 +259,7 @@ func cacheBestBeaconStateOnErrFn(highestSlot primitives.Slot, key [32]byte) cust
// if (state.slot + 1) % SLOTS_PER_EPOCH == 0:
// process_epoch(state)
// state.slot = Slot(state.slot + 1)
func ProcessSlotsCore(ctx context.Context, span trace.Span, state state.BeaconState, slot primitives.Slot, fn customProcessingFn) (state.BeaconState, error) {
func ProcessSlotsCore(ctx context.Context, span *goTrace.Span, state state.BeaconState, slot primitives.Slot, fn customProcessingFn) (state.BeaconState, error) {
var err error
for state.Slot() < slot {
if fn != nil {
@@ -318,7 +318,7 @@ func ProcessEpoch(ctx context.Context, state state.BeaconState) (state.BeaconSta
// UpgradeState upgrades the state to the next version if possible.
func UpgradeState(ctx context.Context, state state.BeaconState) (state.BeaconState, error) {
ctx, span := prysmTrace.StartSpan(ctx, "core.state.UpgradeState")
ctx, span := trace.StartSpan(ctx, "core.state.UpgradeState")
defer span.End()
var err error
@@ -445,9 +445,9 @@ func VerifyOperationLengths(_ context.Context, state state.BeaconState, b interf
// ProcessEpochPrecompute describes the per epoch operations that are performed on the beacon state.
// It's optimized by pre computing validator attested info and epoch total/attested balances upfront.
func ProcessEpochPrecompute(ctx context.Context, state state.BeaconState) (state.BeaconState, error) {
ctx, span := prysmTrace.StartSpan(ctx, "core.state.ProcessEpochPrecompute")
ctx, span := trace.StartSpan(ctx, "core.state.ProcessEpochPrecompute")
defer span.End()
span.SetAttributes(prysmTrace.Int64Attribute("epoch", int64(time.CurrentEpoch(state)))) // lint:ignore uintcast -- This is OK for tracing.
span.AddAttributes(trace.Int64Attribute("epoch", int64(time.CurrentEpoch(state)))) // lint:ignore uintcast -- This is OK for tracing.
if state == nil || state.IsNil() {
return nil, errors.New("nil state")

View File

@@ -114,5 +114,5 @@ func (s *blobStorageCache) evict(key [32]byte) {
func (s *blobStorageCache) updateMetrics(delta float64) {
s.nBlobs += delta
blobDiskCount.Set(s.nBlobs)
blobDiskSize.Set(s.nBlobs * fieldparams.BlobSidecarSize)
blobDiskSize.Set(s.nBlobs * bytesPerSidecar)
}

View File

@@ -21,6 +21,7 @@ import (
)
const retentionBuffer primitives.Epoch = 2
const bytesPerSidecar = 131928
var (
errPruningFailures = errors.New("blobs could not be pruned for some roots")

View File

@@ -70,6 +70,7 @@ go_library(
"@com_github_schollz_progressbar_v3//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@io_etcd_go_bbolt//:go_default_library",
"@io_opencensus_go//trace:go_default_library",
"@org_golang_google_protobuf//proto:go_default_library",
],
)
@@ -116,7 +117,6 @@ go_test(
"//encoding/bytesutil:go_default_library",
"//proto/dbval:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/eth/v1:go_default_library",
"//proto/eth/v2:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/testing:go_default_library",

View File

@@ -5,8 +5,8 @@ import (
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
bolt "go.etcd.io/bbolt"
"go.opencensus.io/trace"
)
// LastArchivedSlot from the db.

View File

@@ -4,9 +4,9 @@ import (
"context"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
"github.com/prysmaticlabs/prysm/v5/proto/dbval"
bolt "go.etcd.io/bbolt"
"go.opencensus.io/trace"
"google.golang.org/protobuf/proto"
)

View File

@@ -5,8 +5,8 @@ import (
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
bolt "go.etcd.io/bbolt"
"go.opencensus.io/trace"
)
// DepositContractAddress returns contract address is the address of

View File

@@ -7,8 +7,8 @@ import (
"github.com/golang/snappy"
fastssz "github.com/prysmaticlabs/fastssz"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"go.opencensus.io/trace"
"google.golang.org/protobuf/proto"
)

View File

@@ -6,9 +6,9 @@ import (
"fmt"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
ethpbv2 "github.com/prysmaticlabs/prysm/v5/proto/eth/v2"
bolt "go.etcd.io/bbolt"
"go.opencensus.io/trace"
)
func (s *Store) SaveLightClientUpdate(ctx context.Context, period uint64, update *ethpbv2.LightClientUpdateWithVersion) error {

View File

@@ -5,179 +5,38 @@ import (
"testing"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
enginev1 "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/runtime/version"
"github.com/prysmaticlabs/prysm/v5/testing/require"
)
func TestStore_LightClientUpdate_CanSaveRetrieveAltair(t *testing.T) {
func TestStore_LightclientUpdate_CanSaveRetrieve(t *testing.T) {
db := setupDB(t)
ctx := context.Background()
update := &ethpbv2.LightClientUpdate{
AttestedHeader: &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderAltair{
HeaderAltair: &ethpbv2.LightClientHeader{
Beacon: &ethpbv1.BeaconBlockHeader{
Slot: 1,
ProposerIndex: 1,
ParentRoot: []byte{1, 1, 1},
StateRoot: []byte{1, 1, 1},
BodyRoot: []byte{1, 1, 1},
},
},
},
},
NextSyncCommittee: &ethpbv2.SyncCommittee{
Pubkeys: nil,
AggregatePubkey: nil,
},
AttestedHeader: nil,
NextSyncCommittee: nil,
NextSyncCommitteeBranch: nil,
FinalizedHeader: &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderAltair{
HeaderAltair: &ethpbv2.LightClientHeader{
Beacon: &ethpbv1.BeaconBlockHeader{
Slot: 1,
ProposerIndex: 1,
ParentRoot: []byte{1, 1, 1},
StateRoot: []byte{1, 1, 1},
BodyRoot: []byte{1, 1, 1},
},
},
},
},
FinalityBranch: nil,
SyncAggregate: nil,
SignatureSlot: 7,
FinalizedHeader: nil,
FinalityBranch: nil,
SyncAggregate: nil,
SignatureSlot: 7,
}
period := uint64(1)
err := db.SaveLightClientUpdate(ctx, period, &ethpbv2.LightClientUpdateWithVersion{
Version: version.Altair,
Version: 1,
Data: update,
})
require.NoError(t, err)
// Retrieve the update
retrievedUpdate, err := db.LightClientUpdate(ctx, period)
require.NoError(t, err)
require.DeepEqual(t, update, retrievedUpdate.Data, "retrieved update does not match saved update")
require.Equal(t, update.SignatureSlot, retrievedUpdate.Data.SignatureSlot, "retrieved update does not match saved update")
}
func TestStore_LightClientUpdate_CanSaveRetrieveCapella(t *testing.T) {
db := setupDB(t)
ctx := context.Background()
update := &ethpbv2.LightClientUpdate{
AttestedHeader: &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderCapella{
HeaderCapella: &ethpbv2.LightClientHeaderCapella{
Beacon: &ethpbv1.BeaconBlockHeader{
Slot: 1,
ProposerIndex: 1,
ParentRoot: []byte{1, 1, 1},
StateRoot: []byte{1, 1, 1},
BodyRoot: []byte{1, 1, 1},
},
Execution: &enginev1.ExecutionPayloadHeaderCapella{
FeeRecipient: []byte{1, 2, 3},
},
ExecutionBranch: [][]byte{{1, 2, 3}, {4, 5, 6}},
},
},
},
NextSyncCommittee: &ethpbv2.SyncCommittee{
Pubkeys: nil,
AggregatePubkey: nil,
},
NextSyncCommitteeBranch: nil,
FinalizedHeader: &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderCapella{
HeaderCapella: &ethpbv2.LightClientHeaderCapella{
Beacon: &ethpbv1.BeaconBlockHeader{
Slot: 1,
ProposerIndex: 1,
ParentRoot: []byte{1, 1, 1},
StateRoot: []byte{1, 1, 1},
BodyRoot: []byte{1, 1, 1},
},
Execution: nil,
ExecutionBranch: nil,
},
},
},
FinalityBranch: nil,
SyncAggregate: nil,
SignatureSlot: 7,
}
period := uint64(1)
err := db.SaveLightClientUpdate(ctx, period, &ethpbv2.LightClientUpdateWithVersion{
Version: version.Capella,
Data: update,
})
require.NoError(t, err)
retrievedUpdate, err := db.LightClientUpdate(ctx, period)
require.NoError(t, err)
require.DeepEqual(t, update, retrievedUpdate.Data, "retrieved update does not match saved update")
}
func TestStore_LightClientUpdate_CanSaveRetrieveDeneb(t *testing.T) {
db := setupDB(t)
ctx := context.Background()
update := &ethpbv2.LightClientUpdate{
AttestedHeader: &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderDeneb{
HeaderDeneb: &ethpbv2.LightClientHeaderDeneb{
Beacon: &ethpbv1.BeaconBlockHeader{
Slot: 1,
ProposerIndex: 1,
ParentRoot: []byte{1, 1, 1},
StateRoot: []byte{1, 1, 1},
BodyRoot: []byte{1, 1, 1},
},
Execution: &enginev1.ExecutionPayloadHeaderDeneb{
FeeRecipient: []byte{1, 2, 3},
},
ExecutionBranch: [][]byte{{1, 2, 3}, {4, 5, 6}},
},
},
},
NextSyncCommittee: &ethpbv2.SyncCommittee{
Pubkeys: nil,
AggregatePubkey: nil,
},
NextSyncCommitteeBranch: nil,
FinalizedHeader: &ethpbv2.LightClientHeaderContainer{
Header: &ethpbv2.LightClientHeaderContainer_HeaderDeneb{
HeaderDeneb: &ethpbv2.LightClientHeaderDeneb{
Beacon: &ethpbv1.BeaconBlockHeader{
Slot: 1,
ProposerIndex: 1,
ParentRoot: []byte{1, 1, 1},
StateRoot: []byte{1, 1, 1},
BodyRoot: []byte{1, 1, 1},
},
Execution: nil,
ExecutionBranch: nil,
},
},
},
FinalityBranch: nil,
SyncAggregate: nil,
SignatureSlot: 7,
}
period := uint64(1)
err := db.SaveLightClientUpdate(ctx, period, &ethpbv2.LightClientUpdateWithVersion{
Version: version.Deneb,
Data: update,
})
require.NoError(t, err)
retrievedUpdate, err := db.LightClientUpdate(ctx, period)
require.NoError(t, err)
require.DeepEqual(t, update, retrievedUpdate.Data, "retrieved update does not match saved update")
}
func TestStore_LightClientUpdates_canRetrieveRange(t *testing.T) {
func TestStore_LightclientUpdates_canRetrieveRange(t *testing.T) {
db := setupDB(t)
ctx := context.Background()
updates := []*ethpbv2.LightClientUpdateWithVersion{

View File

@@ -16,11 +16,11 @@ import (
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/time"
"github.com/prysmaticlabs/prysm/v5/time/slots"
bolt "go.etcd.io/bbolt"
"go.opencensus.io/trace"
)
// State returns the saved state using block's signing root,
@@ -74,7 +74,7 @@ func (s *Store) GenesisState(ctx context.Context) (state.BeaconState, error) {
tracing.AnnotateError(span, err)
return nil, err
}
span.SetAttributes(trace.BoolAttribute("cache_hit", cached != nil))
span.AddAttributes(trace.BoolAttribute("cache_hit", cached != nil))
if cached != nil {
return cached, nil
}

View File

@@ -138,17 +138,20 @@ func TestState_CanSaveRetrieve(t *testing.T) {
require.NoError(t, err)
require.NoError(t, st.SetSlot(100))
p, err := blocks.WrappedExecutionPayloadHeaderElectra(&enginev1.ExecutionPayloadHeaderElectra{
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: []byte("foo"),
BaseFeePerGas: make([]byte, 32),
BlockHash: make([]byte, 32),
TransactionsRoot: make([]byte, 32),
WithdrawalsRoot: make([]byte, 32),
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: []byte("foo"),
BaseFeePerGas: make([]byte, 32),
BlockHash: make([]byte, 32),
TransactionsRoot: make([]byte, 32),
WithdrawalsRoot: make([]byte, 32),
DepositRequestsRoot: make([]byte, 32),
WithdrawalRequestsRoot: make([]byte, 32),
ConsolidationRequestsRoot: make([]byte, 32),
})
require.NoError(t, err)
require.NoError(t, st.SetLatestExecutionPayloadHeader(p))

View File

@@ -20,7 +20,6 @@ go_library(
"//consensus-types/primitives:go_default_library",
"//encoding/bytesutil:go_default_library",
"//io/file:go_default_library",
"//monitoring/tracing/trace:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//time/slots:go_default_library",
"@com_github_golang_snappy//:go_default_library",
@@ -30,6 +29,7 @@ go_library(
"@com_github_prysmaticlabs_fastssz//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@io_etcd_go_bbolt//:go_default_library",
"@io_opencensus_go//trace:go_default_library",
"@org_golang_x_sync//errgroup:go_default_library",
],
)

View File

@@ -14,9 +14,9 @@ import (
slashertypes "github.com/prysmaticlabs/prysm/v5/beacon-chain/slasher/types"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
bolt "go.etcd.io/bbolt"
"go.opencensus.io/trace"
"golang.org/x/sync/errgroup"
)

View File

@@ -164,6 +164,6 @@ func trim(queue *cache.FIFO, maxSize uint64) {
}
// popProcessNoopFunc is a no-op function that never returns an error.
func popProcessNoopFunc(_ interface{}, _ bool) error {
func popProcessNoopFunc(_ interface{}) error {
return nil
}

View File

@@ -31,10 +31,10 @@ func (s *Service) BlockExists(ctx context.Context, hash common.Hash) (bool, *big
if err != nil {
return false, nil, err
}
span.SetAttributes(trace.BoolAttribute("blockCacheHit", true))
span.AddAttributes(trace.BoolAttribute("blockCacheHit", true))
return true, hdrInfo.Number, nil
}
span.SetAttributes(trace.BoolAttribute("blockCacheHit", false))
span.AddAttributes(trace.BoolAttribute("blockCacheHit", false))
header, err := s.HeaderByHash(ctx, hash)
if err != nil {
return false, big.NewInt(0), errors.Wrap(err, "could not query block with given hash")
@@ -56,10 +56,10 @@ func (s *Service) BlockHashByHeight(ctx context.Context, height *big.Int) (commo
if err != nil {
return [32]byte{}, err
}
span.SetAttributes(trace.BoolAttribute("headerCacheHit", true))
span.AddAttributes(trace.BoolAttribute("headerCacheHit", true))
return hInfo.Hash, nil
}
span.SetAttributes(trace.BoolAttribute("headerCacheHit", false))
span.AddAttributes(trace.BoolAttribute("headerCacheHit", false))
if s.rpcClient == nil {
err := errors.New("nil rpc client")

View File

@@ -167,6 +167,15 @@ func (s *Service) NewPayload(ctx context.Context, payload interfaces.ExecutionDa
if err != nil {
return nil, handleRPCError(err)
}
case *pb.ExecutionPayloadElectra:
payloadPb, ok := payload.Proto().(*pb.ExecutionPayloadElectra)
if !ok {
return nil, errors.New("execution data must be a Electra execution payload")
}
err := s.rpcClient.CallContext(ctx, result, NewPayloadMethodV4, payloadPb, versionedHashes, parentBlockRoot)
if err != nil {
return nil, handleRPCError(err)
}
default:
return nil, errors.New("unknown execution data type")
}
@@ -259,6 +268,9 @@ func (s *Service) ForkchoiceUpdated(
func getPayloadMethodAndMessage(slot primitives.Slot) (string, proto.Message) {
pe := slots.ToEpoch(slot)
if pe >= params.BeaconConfig().ElectraForkEpoch {
return GetPayloadMethodV4, &pb.ExecutionPayloadElectraWithValueAndBlobsBundle{}
}
if pe >= params.BeaconConfig().DenebForkEpoch {
return GetPayloadMethodV3, &pb.ExecutionPayloadDenebWithValueAndBlobsBundle{}
}
@@ -554,7 +566,7 @@ func fullPayloadFromPayloadBody(
Transactions: pb.RecastHexutilByteSlice(body.Transactions),
Withdrawals: body.Withdrawals,
}) // We can't get the block value and don't care about the block value for this instance
case version.Deneb, version.Electra:
case version.Deneb:
ebg, err := header.ExcessBlobGas()
if err != nil {
return nil, errors.Wrap(err, "unable to extract ExcessBlobGas attribute from execution payload header")
@@ -583,6 +595,50 @@ func fullPayloadFromPayloadBody(
ExcessBlobGas: ebg,
BlobGasUsed: bgu,
}) // We can't get the block value and don't care about the block value for this instance
case version.Electra:
ebg, err := header.ExcessBlobGas()
if err != nil {
return nil, errors.Wrap(err, "unable to extract ExcessBlobGas attribute from execution payload header")
}
bgu, err := header.BlobGasUsed()
if err != nil {
return nil, errors.Wrap(err, "unable to extract BlobGasUsed attribute from execution payload header")
}
wr, err := pb.JsonWithdrawalRequestsToProto(body.WithdrawalRequests)
if err != nil {
return nil, err
}
dr, err := pb.JsonDepositRequestsToProto(body.DepositRequests)
if err != nil {
return nil, err
}
cr, err := pb.JsonConsolidationRequestsToProto(body.ConsolidationRequests)
if err != nil {
return nil, err
}
return blocks.WrappedExecutionPayloadElectra(
&pb.ExecutionPayloadElectra{
ParentHash: header.ParentHash(),
FeeRecipient: header.FeeRecipient(),
StateRoot: header.StateRoot(),
ReceiptsRoot: header.ReceiptsRoot(),
LogsBloom: header.LogsBloom(),
PrevRandao: header.PrevRandao(),
BlockNumber: header.BlockNumber(),
GasLimit: header.GasLimit(),
GasUsed: header.GasUsed(),
Timestamp: header.Timestamp(),
ExtraData: header.ExtraData(),
BaseFeePerGas: header.BaseFeePerGas(),
BlockHash: header.BlockHash(),
Transactions: pb.RecastHexutilByteSlice(body.Transactions),
Withdrawals: body.Withdrawals,
ExcessBlobGas: ebg,
BlobGasUsed: bgu,
DepositRequests: dr,
WithdrawalRequests: wr,
ConsolidationRequests: cr,
}) // We can't get the block value and don't care about the block value for this instance
default:
return nil, fmt.Errorf("unknown execution block version for payload %d", bVersion)
}
@@ -705,7 +761,7 @@ func buildEmptyExecutionPayload(v int) (proto.Message, error) {
Transactions: make([][]byte, 0),
Withdrawals: make([]*pb.Withdrawal, 0),
}, nil
case version.Deneb, version.Electra:
case version.Deneb:
return &pb.ExecutionPayloadDeneb{
ParentHash: make([]byte, fieldparams.RootLength),
FeeRecipient: make([]byte, fieldparams.FeeRecipientLength),
@@ -719,6 +775,22 @@ func buildEmptyExecutionPayload(v int) (proto.Message, error) {
Transactions: make([][]byte, 0),
Withdrawals: make([]*pb.Withdrawal, 0),
}, nil
case version.Electra:
return &pb.ExecutionPayloadElectra{
ParentHash: make([]byte, fieldparams.RootLength),
FeeRecipient: make([]byte, fieldparams.FeeRecipientLength),
StateRoot: make([]byte, fieldparams.RootLength),
ReceiptsRoot: make([]byte, fieldparams.RootLength),
LogsBloom: make([]byte, fieldparams.LogsBloomLength),
PrevRandao: make([]byte, fieldparams.RootLength),
ExtraData: make([]byte, 0),
BaseFeePerGas: make([]byte, fieldparams.RootLength),
BlockHash: make([]byte, fieldparams.RootLength),
Transactions: make([][]byte, 0),
Withdrawals: make([]*pb.Withdrawal, 0),
WithdrawalRequests: make([]*pb.WithdrawalRequest, 0),
DepositRequests: make([]*pb.DepositRequest, 0),
}, nil
default:
return nil, errors.Wrapf(ErrUnsupportedVersion, "version=%s", version.String(v))
}

View File

@@ -320,6 +320,72 @@ func TestClient_HTTP(t *testing.T) {
blobs := [][]byte{bytesutil.PadTo([]byte("a"), fieldparams.BlobLength), bytesutil.PadTo([]byte("b"), fieldparams.BlobLength)}
require.DeepEqual(t, blobs, resp.BlobsBundle.Blobs)
})
t.Run(GetPayloadMethodV4, func(t *testing.T) {
payloadId := [8]byte{1}
want, ok := fix["ExecutionPayloadElectraWithValue"].(*pb.GetPayloadV4ResponseJson)
require.Equal(t, true, ok)
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
defer func() {
require.NoError(t, r.Body.Close())
}()
enc, err := io.ReadAll(r.Body)
require.NoError(t, err)
jsonRequestString := string(enc)
reqArg, err := json.Marshal(pb.PayloadIDBytes(payloadId))
require.NoError(t, err)
// We expect the JSON string RPC request contains the right arguments.
require.Equal(t, true, strings.Contains(
jsonRequestString, string(reqArg),
))
resp := map[string]interface{}{
"jsonrpc": "2.0",
"id": 1,
"result": want,
}
err = json.NewEncoder(w).Encode(resp)
require.NoError(t, err)
}))
defer srv.Close()
rpcClient, err := rpc.DialHTTP(srv.URL)
require.NoError(t, err)
defer rpcClient.Close()
client := &Service{}
client.rpcClient = rpcClient
// We call the RPC method via HTTP and expect a proper result.
resp, err := client.GetPayload(ctx, payloadId, 2*params.BeaconConfig().SlotsPerEpoch)
require.NoError(t, err)
require.Equal(t, true, resp.OverrideBuilder)
g, err := resp.ExecutionData.ExcessBlobGas()
require.NoError(t, err)
require.DeepEqual(t, uint64(3), g)
g, err = resp.ExecutionData.BlobGasUsed()
require.NoError(t, err)
require.DeepEqual(t, uint64(2), g)
commitments := [][]byte{bytesutil.PadTo([]byte("commitment1"), fieldparams.BLSPubkeyLength), bytesutil.PadTo([]byte("commitment2"), fieldparams.BLSPubkeyLength)}
require.DeepEqual(t, commitments, resp.BlobsBundle.KzgCommitments)
proofs := [][]byte{bytesutil.PadTo([]byte("proof1"), fieldparams.BLSPubkeyLength), bytesutil.PadTo([]byte("proof2"), fieldparams.BLSPubkeyLength)}
require.DeepEqual(t, proofs, resp.BlobsBundle.Proofs)
blobs := [][]byte{bytesutil.PadTo([]byte("a"), fieldparams.BlobLength), bytesutil.PadTo([]byte("b"), fieldparams.BlobLength)}
require.DeepEqual(t, blobs, resp.BlobsBundle.Blobs)
ede, ok := resp.ExecutionData.(interfaces.ExecutionDataElectra)
require.Equal(t, true, ok)
require.NotNil(t, ede.WithdrawalRequests())
wrequestsNotOverMax := len(ede.WithdrawalRequests()) <= int(params.BeaconConfig().MaxWithdrawalRequestsPerPayload)
require.Equal(t, true, wrequestsNotOverMax)
require.NotNil(t, ede.DepositRequests())
drequestsNotOverMax := len(ede.DepositRequests()) <= int(params.BeaconConfig().MaxDepositRequestsPerPayload)
require.Equal(t, true, drequestsNotOverMax)
require.NotNil(t, ede.ConsolidationRequests())
consolidationsNotOverMax := len(ede.ConsolidationRequests()) <= int(params.BeaconConfig().MaxConsolidationsRequestsPerPayload)
require.Equal(t, true, consolidationsNotOverMax)
})
t.Run(ForkchoiceUpdatedMethod+" VALID status", func(t *testing.T) {
forkChoiceState := &pb.ForkchoiceState{
HeadBlockHash: []byte("head"),
@@ -502,6 +568,20 @@ func TestClient_HTTP(t *testing.T) {
require.NoError(t, err)
require.DeepEqual(t, want.LatestValidHash, resp)
})
t.Run(NewPayloadMethodV4+" VALID status", func(t *testing.T) {
execPayload, ok := fix["ExecutionPayloadElectra"].(*pb.ExecutionPayloadElectra)
require.Equal(t, true, ok)
want, ok := fix["ValidPayloadStatus"].(*pb.PayloadStatus)
require.Equal(t, true, ok)
client := newPayloadV4Setup(t, want, execPayload)
// We call the RPC method via HTTP and expect a proper result.
wrappedPayload, err := blocks.WrappedExecutionPayloadElectra(execPayload)
require.NoError(t, err)
resp, err := client.NewPayload(ctx, wrappedPayload, []common.Hash{}, &common.Hash{'a'})
require.NoError(t, err)
require.DeepEqual(t, want.LatestValidHash, resp)
})
t.Run(NewPayloadMethod+" SYNCING status", func(t *testing.T) {
execPayload, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
require.Equal(t, true, ok)
@@ -544,6 +624,20 @@ func TestClient_HTTP(t *testing.T) {
require.ErrorIs(t, ErrAcceptedSyncingPayloadStatus, err)
require.DeepEqual(t, []uint8(nil), resp)
})
t.Run(NewPayloadMethodV4+" SYNCING status", func(t *testing.T) {
execPayload, ok := fix["ExecutionPayloadElectra"].(*pb.ExecutionPayloadElectra)
require.Equal(t, true, ok)
want, ok := fix["SyncingStatus"].(*pb.PayloadStatus)
require.Equal(t, true, ok)
client := newPayloadV4Setup(t, want, execPayload)
// We call the RPC method via HTTP and expect a proper result.
wrappedPayload, err := blocks.WrappedExecutionPayloadElectra(execPayload)
require.NoError(t, err)
resp, err := client.NewPayload(ctx, wrappedPayload, []common.Hash{}, &common.Hash{'a'})
require.ErrorIs(t, ErrAcceptedSyncingPayloadStatus, err)
require.DeepEqual(t, []uint8(nil), resp)
})
t.Run(NewPayloadMethod+" INVALID_BLOCK_HASH status", func(t *testing.T) {
execPayload, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
require.Equal(t, true, ok)
@@ -586,6 +680,20 @@ func TestClient_HTTP(t *testing.T) {
require.ErrorIs(t, ErrInvalidBlockHashPayloadStatus, err)
require.DeepEqual(t, []uint8(nil), resp)
})
t.Run(NewPayloadMethodV4+" INVALID_BLOCK_HASH status", func(t *testing.T) {
execPayload, ok := fix["ExecutionPayloadElectra"].(*pb.ExecutionPayloadElectra)
require.Equal(t, true, ok)
want, ok := fix["InvalidBlockHashStatus"].(*pb.PayloadStatus)
require.Equal(t, true, ok)
client := newPayloadV4Setup(t, want, execPayload)
// We call the RPC method via HTTP and expect a proper result.
wrappedPayload, err := blocks.WrappedExecutionPayloadElectra(execPayload)
require.NoError(t, err)
resp, err := client.NewPayload(ctx, wrappedPayload, []common.Hash{}, &common.Hash{'a'})
require.ErrorIs(t, ErrInvalidBlockHashPayloadStatus, err)
require.DeepEqual(t, []uint8(nil), resp)
})
t.Run(NewPayloadMethod+" INVALID status", func(t *testing.T) {
execPayload, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
require.Equal(t, true, ok)
@@ -628,6 +736,20 @@ func TestClient_HTTP(t *testing.T) {
require.ErrorIs(t, ErrInvalidPayloadStatus, err)
require.DeepEqual(t, want.LatestValidHash, resp)
})
t.Run(NewPayloadMethodV4+" INVALID status", func(t *testing.T) {
execPayload, ok := fix["ExecutionPayloadElectra"].(*pb.ExecutionPayloadElectra)
require.Equal(t, true, ok)
want, ok := fix["InvalidStatus"].(*pb.PayloadStatus)
require.Equal(t, true, ok)
client := newPayloadV4Setup(t, want, execPayload)
// We call the RPC method via HTTP and expect a proper result.
wrappedPayload, err := blocks.WrappedExecutionPayloadElectra(execPayload)
require.NoError(t, err)
resp, err := client.NewPayload(ctx, wrappedPayload, []common.Hash{}, &common.Hash{'a'})
require.ErrorIs(t, ErrInvalidPayloadStatus, err)
require.DeepEqual(t, want.LatestValidHash, resp)
})
t.Run(NewPayloadMethod+" UNKNOWN status", func(t *testing.T) {
execPayload, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
require.Equal(t, true, ok)
@@ -1295,8 +1417,10 @@ func fixtures() map[string]interface{} {
"ExecutionPayload": s.ExecutionPayload,
"ExecutionPayloadCapella": s.ExecutionPayloadCapella,
"ExecutionPayloadDeneb": s.ExecutionPayloadDeneb,
"ExecutionPayloadElectra": s.ExecutionPayloadElectra,
"ExecutionPayloadCapellaWithValue": s.ExecutionPayloadWithValueCapella,
"ExecutionPayloadDenebWithValue": s.ExecutionPayloadWithValueDeneb,
"ExecutionPayloadElectraWithValue": s.ExecutionPayloadWithValueElectra,
"ValidPayloadStatus": s.ValidPayloadStatus,
"InvalidBlockHashStatus": s.InvalidBlockHashStatus,
"AcceptedStatus": s.AcceptedStatus,
@@ -1434,6 +1558,40 @@ func fixturesStruct() *payloadFixtures {
TargetPubkey: &tPubkey,
}
}
dr, err := pb.JsonDepositRequestsToProto(depositRequests)
if err != nil {
panic(err)
}
wr, err := pb.JsonWithdrawalRequestsToProto(withdrawalRequests)
if err != nil {
panic(err)
}
cr, err := pb.JsonConsolidationRequestsToProto(consolidationRequests)
if err != nil {
panic(err)
}
executionPayloadFixtureElectra := &pb.ExecutionPayloadElectra{
ParentHash: foo[:],
FeeRecipient: bar,
StateRoot: foo[:],
ReceiptsRoot: foo[:],
LogsBloom: baz,
PrevRandao: foo[:],
BlockNumber: 1,
GasLimit: 1,
GasUsed: 1,
Timestamp: 1,
ExtraData: foo[:],
BaseFeePerGas: bytesutil.PadTo(baseFeePerGas.Bytes(), fieldparams.RootLength),
BlockHash: foo[:],
Transactions: [][]byte{foo[:]},
Withdrawals: []*pb.Withdrawal{},
BlobGasUsed: 2,
ExcessBlobGas: 3,
DepositRequests: dr,
WithdrawalRequests: wr,
ConsolidationRequests: cr,
}
hexUint := hexutil.Uint64(1)
executionPayloadWithValueFixtureCapella := &pb.GetPayloadV2ResponseJson{
ExecutionPayload: &pb.ExecutionPayloadCapellaJSON{
@@ -1483,6 +1641,36 @@ func fixturesStruct() *payloadFixtures {
Blobs: []hexutil.Bytes{{'a'}, {'b'}},
},
}
executionPayloadWithValueFixtureElectra := &pb.GetPayloadV4ResponseJson{
ShouldOverrideBuilder: true,
ExecutionPayload: &pb.ExecutionPayloadElectraJSON{
ParentHash: &common.Hash{'a'},
FeeRecipient: &common.Address{'b'},
StateRoot: &common.Hash{'c'},
ReceiptsRoot: &common.Hash{'d'},
LogsBloom: &hexutil.Bytes{'e'},
PrevRandao: &common.Hash{'f'},
BaseFeePerGas: "0x123",
BlockHash: &common.Hash{'g'},
Transactions: []hexutil.Bytes{{'h'}},
Withdrawals: []*pb.Withdrawal{},
BlockNumber: &hexUint,
GasLimit: &hexUint,
GasUsed: &hexUint,
Timestamp: &hexUint,
BlobGasUsed: &bgu,
ExcessBlobGas: &ebg,
DepositRequests: depositRequests,
WithdrawalRequests: withdrawalRequests,
ConsolidationRequests: consolidationRequests,
},
BlockValue: "0x11fffffffff",
BlobsBundle: &pb.BlobBundleJSON{
Commitments: []hexutil.Bytes{[]byte("commitment1"), []byte("commitment2")},
Proofs: []hexutil.Bytes{[]byte("proof1"), []byte("proof2")},
Blobs: []hexutil.Bytes{{'a'}, {'b'}},
},
}
parent := bytesutil.PadTo([]byte("parentHash"), fieldparams.RootLength)
sha3Uncles := bytesutil.PadTo([]byte("sha3Uncles"), fieldparams.RootLength)
miner := bytesutil.PadTo([]byte("miner"), fieldparams.FeeRecipientLength)
@@ -1574,8 +1762,10 @@ func fixturesStruct() *payloadFixtures {
ExecutionPayloadCapella: executionPayloadFixtureCapella,
ExecutionPayloadDeneb: executionPayloadFixtureDeneb,
EmptyExecutionPayloadDeneb: emptyExecutionPayloadDeneb,
ExecutionPayloadElectra: executionPayloadFixtureElectra,
ExecutionPayloadWithValueCapella: executionPayloadWithValueFixtureCapella,
ExecutionPayloadWithValueDeneb: executionPayloadWithValueFixtureDeneb,
ExecutionPayloadWithValueElectra: executionPayloadWithValueFixtureElectra,
ValidPayloadStatus: validStatus,
InvalidBlockHashStatus: inValidBlockHashStatus,
AcceptedStatus: acceptedStatus,
@@ -1597,8 +1787,10 @@ type payloadFixtures struct {
ExecutionPayloadCapella *pb.ExecutionPayloadCapella
EmptyExecutionPayloadDeneb *pb.ExecutionPayloadDeneb
ExecutionPayloadDeneb *pb.ExecutionPayloadDeneb
ExecutionPayloadElectra *pb.ExecutionPayloadElectra
ExecutionPayloadWithValueCapella *pb.GetPayloadV2ResponseJson
ExecutionPayloadWithValueDeneb *pb.GetPayloadV3ResponseJson
ExecutionPayloadWithValueElectra *pb.GetPayloadV4ResponseJson
ValidPayloadStatus *pb.PayloadStatus
InvalidBlockHashStatus *pb.PayloadStatus
AcceptedStatus *pb.PayloadStatus
@@ -1957,6 +2149,40 @@ func newPayloadV3Setup(t *testing.T, status *pb.PayloadStatus, payload *pb.Execu
return service
}
func newPayloadV4Setup(t *testing.T, status *pb.PayloadStatus, payload *pb.ExecutionPayloadElectra) *Service {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
defer func() {
require.NoError(t, r.Body.Close())
}()
enc, err := io.ReadAll(r.Body)
require.NoError(t, err)
jsonRequestString := string(enc)
reqArg, err := json.Marshal(payload)
require.NoError(t, err)
// We expect the JSON string RPC request contains the right arguments.
require.Equal(t, true, strings.Contains(
jsonRequestString, string(reqArg),
))
resp := map[string]interface{}{
"jsonrpc": "2.0",
"id": 1,
"result": status,
}
err = json.NewEncoder(w).Encode(resp)
require.NoError(t, err)
}))
rpcClient, err := rpc.DialHTTP(srv.URL)
require.NoError(t, err)
service := &Service{}
service.rpcClient = rpcClient
return service
}
func TestReconstructBlindedBlockBatch(t *testing.T) {
t.Run("empty response works", func(t *testing.T) {
ctx := context.Background()

View File

@@ -64,6 +64,12 @@ func payloadToBody(t *testing.T, ed interfaces.ExecutionData) *pb.ExecutionPaylo
for i := range txs {
body.Transactions = append(body.Transactions, txs[i])
}
eed, isElectra := ed.(interfaces.ExecutionDataElectra)
if isElectra {
body.DepositRequests = pb.ProtoDepositRequestsToJson(eed.DepositRequests())
body.WithdrawalRequests = pb.ProtoWithdrawalRequestsToJson(eed.WithdrawalRequests())
body.ConsolidationRequests = pb.ProtoConsolidationRequestsToJson(eed.ConsolidationRequests())
}
return body
}
@@ -126,7 +132,7 @@ func testBlindedBlockFixtures(t *testing.T) *blindedBlockFixtures {
afterSkipBlock, _ := util.GenerateTestDenebBlockWithSidecar(t, [32]byte{}, denebSlot(t)+3, 0, util.WithPayloadSetter(afterSkip))
fx.afterSkipDeneb = blindedBlockWithHeader(t, afterSkipBlock)
electra := fixturesStruct().ExecutionPayloadDeneb
electra := fixturesStruct().ExecutionPayloadElectra
electra.BlockHash = bytesutil.PadTo([]byte("electra"), 32)
electra.BlockNumber = 5
electraBlock, _ := util.GenerateTestElectraBlockWithSidecar(t, [32]byte{}, electraSlot(t), 0, util.WithElectraPayload(electra))
@@ -158,7 +164,6 @@ func TestPayloadBodiesViaUnblinder(t *testing.T) {
payload, err := bbr.payloadForHeader(fx.denebBlock.blinded.header, fx.denebBlock.blinded.block.Version())
require.NoError(t, err)
require.Equal(t, version.Deneb, fx.denebBlock.blinded.block.Version())
unblindFull, err := blocks.BuildSignedBeaconBlockFromExecutionPayload(fx.denebBlock.blinded.block, payload)
require.NoError(t, err)
testAssertReconstructedEquivalent(t, fx.denebBlock.full, unblindFull)

View File

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

View File

@@ -65,6 +65,7 @@ go_library(
"//runtime/prereqs:go_default_library",
"//runtime/version:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_gorilla_mux//:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_prometheus_client_golang//prometheus:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
@@ -81,7 +82,6 @@ go_test(
],
embed = [":go_default_library"],
deps = [
"//api/server/middleware:go_default_library",
"//beacon-chain/blockchain:go_default_library",
"//beacon-chain/builder:go_default_library",
"//beacon-chain/core/feed/state:go_default_library",

View File

@@ -8,12 +8,12 @@ import (
"github.com/prysmaticlabs/prysm/v5/cmd/beacon-chain/flags"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing"
tracing2 "github.com/prysmaticlabs/prysm/v5/monitoring/tracing"
"github.com/urfave/cli/v2"
)
func configureTracing(cliCtx *cli.Context) error {
return tracing.Setup(
return tracing2.Setup(
"beacon-chain", // service name
cliCtx.String(cmd.TracingProcessNameFlag.Name),
cliCtx.String(cmd.TracingEndpointFlag.Name),

View File

@@ -8,7 +8,6 @@ import (
"context"
"fmt"
"net"
"net/http"
"os"
"os/signal"
"path/filepath"
@@ -18,6 +17,7 @@ import (
"syscall"
"github.com/ethereum/go-ethereum/common"
"github.com/gorilla/mux"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v5/api/server/httprest"
"github.com/prysmaticlabs/prysm/v5/api/server/middleware"
@@ -361,7 +361,7 @@ func registerServices(cliCtx *cli.Context, beacon *BeaconNode, synchronizer *sta
}
log.Debugln("Registering RPC Service")
router := http.NewServeMux()
router := newRouter(cliCtx)
if err := beacon.registerRPCService(router); err != nil {
return errors.Wrap(err, "could not register RPC service")
}
@@ -397,8 +397,21 @@ func initSyncWaiter(ctx context.Context, complete chan struct{}) func() error {
}
}
func newRouter(cliCtx *cli.Context) *mux.Router {
var allowedOrigins []string
if cliCtx.IsSet(flags.HTTPServerCorsDomain.Name) {
allowedOrigins = strings.Split(cliCtx.String(flags.HTTPServerCorsDomain.Name), ",")
} else {
allowedOrigins = strings.Split(flags.HTTPServerCorsDomain.Value, ",")
}
r := mux.NewRouter()
r.Use(middleware.NormalizeQueryValuesHandler)
r.Use(middleware.CorsHandler(allowedOrigins))
return r
}
// StateFeed implements statefeed.Notifier.
func (b *BeaconNode) StateFeed() event.SubscriberSender {
func (b *BeaconNode) StateFeed() *event.Feed {
return b.stateFeed
}
@@ -408,7 +421,7 @@ func (b *BeaconNode) BlockFeed() *event.Feed {
}
// OperationFeed implements opfeed.Notifier.
func (b *BeaconNode) OperationFeed() event.SubscriberSender {
func (b *BeaconNode) OperationFeed() *event.Feed {
return b.opFeed
}
@@ -903,7 +916,7 @@ func (b *BeaconNode) registerSlasherService() error {
return b.services.RegisterService(slasherSrv)
}
func (b *BeaconNode) registerRPCService(router *http.ServeMux) error {
func (b *BeaconNode) registerRPCService(router *mux.Router) error {
var chainService *blockchain.Service
if err := b.services.FetchService(&chainService); err != nil {
return err
@@ -1030,26 +1043,13 @@ func (b *BeaconNode) registerPrometheusService(_ *cli.Context) error {
return b.services.RegisterService(service)
}
func (b *BeaconNode) registerHTTPService(router *http.ServeMux) error {
func (b *BeaconNode) registerHTTPService(router *mux.Router) error {
host := b.cliCtx.String(flags.HTTPServerHost.Name)
port := b.cliCtx.Int(flags.HTTPServerPort.Name)
address := net.JoinHostPort(host, strconv.Itoa(port))
var allowedOrigins []string
if b.cliCtx.IsSet(flags.HTTPServerCorsDomain.Name) {
allowedOrigins = strings.Split(b.cliCtx.String(flags.HTTPServerCorsDomain.Name), ",")
} else {
allowedOrigins = strings.Split(flags.HTTPServerCorsDomain.Value, ",")
}
middlewares := []middleware.Middleware{
middleware.NormalizeQueryValuesHandler,
middleware.CorsHandler(allowedOrigins),
}
opts := []httprest.Option{
httprest.WithRouter(router),
httprest.WithHTTPAddr(address),
httprest.WithMiddlewares(middlewares),
}
if b.cliCtx.IsSet(cmd.ApiTimeoutFlag.Name) {
opts = append(opts, httprest.WithTimeout(b.cliCtx.Duration(cmd.ApiTimeoutFlag.Name)))

View File

@@ -12,7 +12,6 @@ import (
"testing"
"time"
"github.com/prysmaticlabs/prysm/v5/api/server/middleware"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/blockchain"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/builder"
statefeed "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/feed/state"
@@ -253,19 +252,19 @@ func Test_hasNetworkFlag(t *testing.T) {
}
func TestCORS(t *testing.T) {
router := http.NewServeMux()
// Ensure a test route exists
router.HandleFunc("/some-path", func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodGet {
w.WriteHeader(http.StatusOK)
} else {
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
}
})
// Mock CLI context with a test CORS domain
app := cli.App{}
set := flag.NewFlagSet("test", 0)
set.String(flags.HTTPServerCorsDomain.Name, "http://allowed-example.com", "")
cliCtx := cli.NewContext(&app, set, nil)
require.NoError(t, cliCtx.Set(flags.HTTPServerCorsDomain.Name, "http://allowed-example.com"))
// Register the CORS middleware on mux Router
allowedOrigins := []string{"http://allowed-example.com"}
handler := middleware.CorsHandler(allowedOrigins)(router)
router := newRouter(cliCtx)
// Ensure a test route exists
router.HandleFunc("/some-path", func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
}).Methods(http.MethodGet)
// Define test cases
tests := []struct {
@@ -286,7 +285,7 @@ func TestCORS(t *testing.T) {
rr := httptest.NewRecorder()
// Serve HTTP
handler.ServeHTTP(rr, req)
router.ServeHTTP(rr, req)
// Check the CORS headers based on the expected outcome
if tc.expectAllow && rr.Header().Get("Access-Control-Allow-Origin") != tc.origin {

View File

@@ -21,7 +21,6 @@ go_library(
"//config/features:go_default_library",
"//config/params:go_default_library",
"//consensus-types/primitives:go_default_library",
"//monitoring/tracing/trace:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/attestation:go_default_library",
"//proto/prysm/v1alpha1/attestation/aggregation/attestations:go_default_library",
@@ -33,6 +32,7 @@ go_library(
"@com_github_prometheus_client_golang//prometheus/promauto:go_default_library",
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@io_opencensus_go//trace:go_default_library",
],
)

View File

@@ -16,7 +16,6 @@ go_library(
"//beacon-chain/core/helpers:go_default_library",
"//config/params:go_default_library",
"//consensus-types/primitives:go_default_library",
"//monitoring/tracing/trace:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/attestation:go_default_library",
"//proto/prysm/v1alpha1/attestation/aggregation/attestations:go_default_library",
@@ -25,6 +24,7 @@ go_library(
"@com_github_pkg_errors//:go_default_library",
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@io_opencensus_go//trace:go_default_library",
],
)

View File

@@ -8,12 +8,12 @@ import (
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1/attestation"
attaggregation "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1/attestation/aggregation/attestations"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
log "github.com/sirupsen/logrus"
"go.opencensus.io/trace"
)
// AggregateUnaggregatedAttestations aggregates the unaggregated attestations and saves the

View File

@@ -6,10 +6,10 @@ import (
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1/attestation"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"go.opencensus.io/trace"
)
// SaveUnaggregatedAttestation saves an unaggregated attestation in cache.

Some files were not shown because too many files have changed in this diff Show More