Compare commits

...

31 Commits

Author SHA1 Message Date
Nishant Das
bc9151d647 Fix Multivalue Slice Deadlock (#13087)
* fix deadlock

* gofmt

* lint

(cherry picked from commit f91efafe24)
2023-10-23 06:49:21 -05:00
Preston Van Loon
747d7b5190 rpc/apimiddleware: Test all paths can be created (#13073)
(cherry picked from commit f592bf7f07)
2023-10-18 19:39:10 -05:00
james-prysm
05874df18a removing bad path
(cherry picked from commit a7e56058c1)
2023-10-18 19:38:51 -05:00
Radosław Kapka
44973b0bb3 Using the multi value slice for the beacon state (#12549)
* in progress...

* in progress...

* remove log

* log root

* Revert "Auxiliary commit to revert individual files from f12a609ea2a2f1e87e97321f3a717cd324b5ae97"

This reverts commit 5ae35edb6477d8d0ea4e94b273efc6590484da85.

* cleanup

* remove log

* remove whitespace

* remove logs

* more stuff

* copy

* always rebuild trie

* revert

* add state

* init state

* fix all

* uintptr

* move slice to new package

* lock in `Detach`

* remove constraint

* reorder

* blockroots and stateroots

* fill roots in empty()

* fix hasher

* implement slice for balances and inactivity scores

* detach in setters

* Revert "implement slice for balances and inactivity scores"

This reverts commit 59eb9df8d7.

# Conflicts:
#	beacon-chain/state/state-native/setters_validator.go

* use counter to track states

* typos

* rename interface

* balances

* gauge

* some improvements

* first try with map

* fix

* inactivity scores in progress

* fix test

# Conflicts:
#	beacon-chain/state/state-native/helpers_test.go

* test fixes

* ToProto fix

* copy roots

* validators

* build fixes

* fix bug in `ToProto`

* fix fuzz test

* fix bug in slice getters

* fix state equality checks

* make tests pass

* make tests pass

* more test updates

* Revert "Auxiliary commit to revert individual files from 34e7344bff08a589e6341bb1829e3cb74159e878"

This reverts commit ecd64efa8917f37ca41460e0356ff007fe55dd9d.

* Revert "make tests pass"

This reverts commit 0cf00f19ee.

* Revert "make tests pass"

This reverts commit 521b65e1d2.

* pass tests

* deepequal identifiable types

* Deflake `cloners_test.go`

* feature flag for block roots

* feature flag

* remove recursive locks

* reduce complexity of rootSelector

* fix randao mixes root

* some fixes

* revisit tests

* revert change to field trie helpers

* initialize field map for tests

* remove whitespace

* initialize roots with proper length

* more fixes

* out of bounds message fix

* optimize length calculation

* remove call to Len in PubkeyAtIndex

* don't log deposits

* unit tests

* unit tests

* fix

* comments

* test fixes

* id

* remove Enumerator interface

* review feedback

* simplify field trie

* bring back fieldtrie package

* fix bazel file

* use handle32ByteArrays for root computation

* fix locks

* metrics

* bzl

* simplify some things

* use htr in state test

* remove code from require package

* gzl

* more htr

* Fuzzing of the multi-value slice

* assert values

* getter optimizations

* use At when reading from validators

* Nishant's review

* restore safe copy

* remove empty line

* build fix

* restore how we get root at index for deafult mode

* more review comments

* optimize default behavior

* simplify Slice calls

* test fix

* remove unnecessary package

* remove unused setter

* make fieldMap unexported

* some improvements in state package

* call `Slice` instead of manually copying

* unlock in ReadFromEveryValidator

* Potuz's comments

* lock the state when reading from all validators

# Conflicts:
#	beacon-chain/state/state-native/getters_validator.go

* add back preston's changes

* add index

---------

Co-authored-by: Potuz <potuz@prysmaticlabs.com>
Co-authored-by: nisdas <nishdas93@gmail.com>
Co-authored-by: Preston Van Loon <pvanloon@offchainlabs.com>
2023-10-06 01:10:05 +00:00
Preston Van Loon
de0c7e6256 update go 1.20.9 (#13009) 2023-10-05 22:11:05 +00:00
Nishant Das
c1c0cd040c Fix Initial Sync PreProcessing (#13007)
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2023-10-05 15:18:53 +00:00
Nishant Das
734eb98941 Fix Long Running E2E (#13000) 2023-10-05 14:37:11 +00:00
Nishant Das
ffaef83634 Build Blocks in Parallel Permanently (#13008) 2023-10-05 06:45:11 -07:00
terencechain
f9a40ef111 Handle wrapped invalid block error (#12982)
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2023-10-04 18:16:35 +00:00
Radosław Kapka
7454041356 Use middleware to handle comma-separated query params (#12995) 2023-10-04 15:49:42 +02:00
Radosław Kapka
f37301c0c0 Remove remote slashing protection feature (#12989)
* Remove remote slashing protection feature

* test fix

* remove mock from tests

---------

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2023-10-04 04:15:06 +00:00
Nishant Das
cf1bfb9d67 Make New Engine Methods The Default (#12997) 2023-10-04 01:44:31 +00:00
Potuz
9d8dd5c9ad Don't prune proposer ID cache in a loop (#12996)
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2023-10-03 23:25:53 +00:00
Delweng
f812bdcf60 beacon-node/state: alloc 1more item for append case (#12832)
* beacon-chain/state/attenstation: alloc +1 items for append

Signed-off-by: jsvisa <delweng@gmail.com>

* beacon-chain/state/eth1: alloc +1 items for append

Signed-off-by: jsvisa <delweng@gmail.com>

* beacon-chain/state/misc: alloc +1 items for append

Signed-off-by: jsvisa <delweng@gmail.com>

* beacon-chain/state/participation: alloc +1 items for append

Signed-off-by: jsvisa <delweng@gmail.com>

* beacon-chain/state/validator: alloc +1 items for append

Signed-off-by: jsvisa <delweng@gmail.com>

* Add some benchmarks

* Evaluate append vs copy. Apply results

* fix copy issue

* revert copy changes from a5ba8d4352

---------

Signed-off-by: jsvisa <delweng@gmail.com>
Co-authored-by: Nishant Das <nishdas93@gmail.com>
Co-authored-by: Preston Van Loon <pvanloon@offchainlabs.com>
2023-10-03 20:41:55 +00:00
terencechain
58c0899676 Don't mark block as bad in validateBeaconBlock for pending queue (#12983)
* Don't mark block as bad in validateBeaconBlock for pending queue

* Fix tests
2023-10-03 16:36:23 +00:00
terencechain
4628c19f51 Refactor churn limit helpers (#12971) 2023-10-03 14:14:41 +00:00
Radosław Kapka
58f23d2302 Handle hex in Blocker, Stater and optimistic mode checker (#12979)
* Handle hex in `Blocker`

* hex in stater

* ineff fix

* optimistic mode

---------

Co-authored-by: Nishant Das <nishdas93@gmail.com>
2023-10-03 05:52:29 +00:00
Potuz
9e33723b26 Revert "Do not cache proposer ID on GetProposerDuties (#12939)" (#12986)
This reverts commit e2591f7c5b.

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2023-10-03 04:04:17 +00:00
Potuz
2c32a87d17 Tweak LastRoot to return head root (#12985) 2023-10-03 02:22:52 +00:00
Potuz
56f3dafb54 Lock forkchoice on late block tasks (#12978)
Co-authored-by: Nishant Das <nishdas93@gmail.com>
2023-10-02 17:07:03 +00:00
Nicolás Pernas Maradei
70380660b3 [1/5] Light client sync protocol (#12853)
* generate SyncCommittee SSZ

* refactor error handling

* rewards: use http2.HandleError

* add light client protobuf files

* add light client helpers
2023-10-02 15:34:34 +00:00
Radosław Kapka
ecd55e5462 Remove go-playground/validator from Beacon API (#12973)
* Remove go-playground/validator from Beacon API

* gzl

---------

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2023-10-02 13:21:59 +00:00
Nishant Das
46b2442127 Do Not Calculate Churn With 0 Exits (#12976) 2023-10-02 01:46:58 +00:00
Radosław Kapka
d8b2d9060f Return RpcError from core service's SubmitSyncMessage (#12974)
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2023-09-30 14:19:09 +00:00
Justin Traglia
b667c68c87 Default to the portable version of blst (#12720)
* Default to the portable version of blst

* Update based on review comments

---------

Co-authored-by: Preston Van Loon <pvanloon@offchainlabs.com>
2023-09-29 15:35:15 -05:00
Lucas Saldanha
fb19ee8895 Updating Teku mainnet bootnodes ENRs (#12962)
Co-authored-by: Nishant Das <nishdas93@gmail.com>
Co-authored-by: Preston Van Loon <pvanloon@offchainlabs.com>
2023-09-29 10:11:58 +00:00
terencechain
51b8075474 Use skip mev-boost flag for GetBlock RPC (#12969)
Co-authored-by: Nishant Das <nishdas93@gmail.com>
2023-09-29 16:48:40 +08:00
Radosław Kapka
367504f403 Support comma-separated query params in Beacon API (#12966) 2023-09-29 15:40:23 +08:00
Potuz
b4e72f1e19 Deneb spectests release v1.4.0-beta.2-hotfix (#12959)
* Update and use max per epoch churn limit

* Update spec tests

* Fix e2e test

* deneb fork epoch condition

* Fix lint and better casting

* fix ordering

* fix check

* gaz

* Fix more tests

* Apply proposer boost to first block in equivocation

* Increase timeout

* Don't increase timeout, it's not the reason

* implement deneb forkchoice spectests

expose ReceiveBlob from the blockchain package

* spin_off_helper

* remove minimal tests

* Terence's review

* Add process register test for Deneb

* Terence's suggestion

Co-authored-by: terencechain <terence@prysmaticlabs.com>

* fix forkchoice minimal

* fix minimal sha

* general sha

* different repos

* different repos

---------

Co-authored-by: terence tsao <terence@prysmaticlabs.com>
Co-authored-by: nisdas <nishdas93@gmail.com>
2023-09-28 21:05:23 +00:00
Preston Van Loon
a7361cd5ab Docker: Add "manual" build tag to reduce build times in CI (#12967)
* Add manual tags to oci images. This reduces build times for build and test in CI.

* Ran buildifier on tools dir
2023-09-28 17:49:26 +00:00
Preston Van Loon
02ee6897bb Multiarch docker containers (#12428)
* Add bazel-zig-cc for a hermetic cc toolchain

* gazelle

* Remove llvm

* remove wl

* Add new URLs for renamed repo

* gazelle

* Update to v2.0.0-rc1

* bump to rc2

* Proof of concept multi-arch containers for beacon-chain

* TODO and gaz

* Refactor to starlark macro. Use a version of bash that actually works

* progress

* gaz

* multirun to use multiple repositories, but doesn't work with tag stamping

* Revert "multirun to use multiple repositories, but doesn't work with tag stamping"

This reverts commit 93afa76f65.

* Add targets for all supported docker images and temporarily set the repository to prysm-dev for testing

* use a temporary fix to see if it works on buildkite

* Revert "use a temporary fix to see if it works on buildkite"

This reverts commit ddc79283ca.

* testing a cURL fix

* try fix with my fix

* Revert "try fix with my fix"

This reverts commit bb7521bf47.

* Revert "testing a cURL fix"

This reverts commit 8a4782110f.

* try tip of main branch for rules_oci

* update to 1.2.0

* Update rules_oci to v1.3.0

* Update rule_oci to 1.3.4

* Disable experimental_remote_downloader

* Remove extra zig bazelrc

* Move image deps to its own file

* PR feedback

---------

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2023-09-28 15:24:16 +00:00
212 changed files with 4473 additions and 3327 deletions

View File

@@ -15,7 +15,7 @@ coverage --define=coverage_enabled=1
# Stamp binaries with git information
build --workspace_status_command=./hack/workspace_status.sh
build --define blst_disabled=false --define blst_modern=true
build --define blst_disabled=false
run --define blst_disabled=false
build:blst_disabled --define blst_disabled=true

View File

@@ -12,7 +12,8 @@
#build:remote-cache --disk_cache=
build:remote-cache --remote_download_toplevel
build:remote-cache --remote_cache=grpc://bazel-remote-cache:9092
build:remote-cache --experimental_remote_downloader=grpc://bazel-remote-cache:9092
# Does not work with rules_oci. See https://github.com/bazel-contrib/rules_oci/issues/292
#build:remote-cache --experimental_remote_downloader=grpc://bazel-remote-cache:9092
build:remote-cache --remote_local_fallback
build:remote-cache --experimental_remote_cache_async
build:remote-cache --experimental_remote_merkle_tree_cache

View File

@@ -75,14 +75,14 @@ jobs:
- name: Build
# Use blst tag to allow go and bazel builds for blst.
run: go build -v ./...
env:
CGO_CFLAGS: "-O -D__BLST_PORTABLE__"
env:
CGO_CFLAGS: "-O2 -D__BLST_PORTABLE__"
# fuzz leverage go tag based stubs at compile time.
# Building and testing with these tags should be checked and enforced at pre-submit.
- name: Test for fuzzing
run: go test -tags=fuzz,develop ./... -test.run=^Fuzz
env:
CGO_CFLAGS: "-O -D__BLST_PORTABLE__"
env:
CGO_CFLAGS: "-O2 -D__BLST_PORTABLE__"
# Tests run via Bazel for now...
# - name: Test

View File

@@ -50,8 +50,6 @@ load("@prysm//tools/cross-toolchain:prysm_toolchains.bzl", "configure_prysm_tool
configure_prysm_toolchains()
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "bazel_skylib",
sha256 = "1c531376ac7e5a180e0237938a2536de0c54d93f5c278634818e0efc952dd56c",
@@ -87,6 +85,24 @@ http_archive(
urls = ["https://github.com/bazelbuild/rules_docker/releases/download/v0.25.0/rules_docker-v0.25.0.tar.gz"],
)
http_archive(
name = "rules_oci",
sha256 = "c71c25ed333a4909d2dd77e0b16c39e9912525a98c7fa85144282be8d04ef54c",
strip_prefix = "rules_oci-1.3.4",
url = "https://github.com/bazel-contrib/rules_oci/releases/download/v1.3.4/rules_oci-v1.3.4.tar.gz",
)
load("@rules_oci//oci:dependencies.bzl", "rules_oci_dependencies")
rules_oci_dependencies()
load("@rules_oci//oci:repositories.bzl", "LATEST_CRANE_VERSION", "oci_register_toolchains")
oci_register_toolchains(
name = "oci",
crane_version = LATEST_CRANE_VERSION,
)
http_archive(
name = "io_bazel_rules_go",
patch_args = ["-p1"],
@@ -167,12 +183,30 @@ container_pull(
repository = "pinglamb/alpine-glibc",
)
load("@rules_oci//oci:pull.bzl", "oci_pull")
# A multi-arch base image
oci_pull(
name = "linux_debian11_multiarch_base", # Debian bullseye
digest = "sha256:9b8e0854865dcaf49470b4ec305df45957020fbcf17b71eeb50ffd3bc5bf885d", # 2023-05-17
image = "gcr.io/distroless/cc-debian11",
platforms = [
"linux/amd64",
"linux/arm64",
],
reproducible = True,
)
load("@prysm//tools:image_deps.bzl", "prysm_image_deps")
prysm_image_deps()
load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
go_rules_dependencies()
go_register_toolchains(
go_version = "1.20.7",
go_version = "1.20.9",
nogo = "@//:nogo",
)
@@ -213,7 +247,9 @@ filegroup(
url = "https://github.com/ethereum/EIPs/archive/5480440fe51742ed23342b68cf106cefd427e39d.tar.gz",
)
consensus_spec_version = "v1.4.0-beta.1"
consensus_spec_test_version = "v1.4.0-beta.2-hotfix"
consensus_spec_version = "v1.4.0-beta.2"
bls_test_version = "v0.1.1"
@@ -229,8 +265,8 @@ filegroup(
visibility = ["//visibility:public"],
)
""",
sha256 = "24399b60ce3fbeb2311952d213dc3731b6dcb0f8881b016c283de5b518d2bbba",
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/general.tar.gz" % consensus_spec_version,
sha256 = "99770a001189f66204a4ef79161c8002bcbbcbd8236f1c6479bd5b83a3c68d42",
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/general.tar.gz" % consensus_spec_test_version,
)
http_archive(
@@ -245,8 +281,8 @@ filegroup(
visibility = ["//visibility:public"],
)
""",
sha256 = "8e656ee48d2e2ebc9cf9baedb81f27925bc625b3e3fbb2883444a08758a5884a",
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/minimal.tar.gz" % consensus_spec_version,
sha256 = "56763f6492ee137108271007d62feef60d8e3f1698e53dee4bc4b07e55f7326b",
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/minimal.tar.gz" % consensus_spec_test_version,
)
http_archive(
@@ -261,8 +297,8 @@ filegroup(
visibility = ["//visibility:public"],
)
""",
sha256 = "8bd137da6cc57a25383bfac5bc37e31265098145278bd8002b88e24c8b4718b9",
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/mainnet.tar.gz" % consensus_spec_version,
sha256 = "bc1cac1a991cdc7426efea14385dcf215df85ed3f0572b824ad6a1d7ca0c89ad",
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/mainnet.tar.gz" % consensus_spec_test_version,
)
http_archive(
@@ -276,7 +312,7 @@ filegroup(
visibility = ["//visibility:public"],
)
""",
sha256 = "2bc1edb6e4a4f86c00317c04618a90b0ca29ee1eba833d0a64dd67fdd83fdbe3",
sha256 = "c5898001aaab2a5bb38a39ff9d17a52f1f9befcc26e63752cbf556040f0c884e",
strip_prefix = "consensus-specs-" + consensus_spec_version[1:],
url = "https://github.com/ethereum/consensus-specs/archive/refs/tags/%s.tar.gz" % consensus_spec_version,
)
@@ -337,9 +373,6 @@ http_archive(
],
)
# Group the sources of the library so that CMake rule have access to it
all_content = """filegroup(name = "all", srcs = glob(["**"]), visibility = ["//visibility:public"])"""
# External dependencies
load("//:deps.bzl", "prysm_deps")

View File

@@ -12,6 +12,7 @@ go_library(
"head.go",
"head_sync_committee_info.go",
"init_sync_process_block.go",
"lightclient.go",
"log.go",
"merge_ascii_art.go",
"metrics.go",
@@ -77,6 +78,8 @@ go_library(
"//monitoring/tracing: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",
"//proto/prysm/v1alpha1/attestation:go_default_library",
"//runtime/version:go_default_library",

View File

@@ -70,11 +70,8 @@ func IsInvalidBlock(e error) bool {
if e == nil {
return false
}
_, ok := e.(invalidBlockError)
if !ok {
return IsInvalidBlock(errors.Unwrap(e))
}
return true
var d invalidBlockError
return errors.As(e, &d)
}
// InvalidBlockLVH returns the invalid block last valid hash root. If the error
@@ -83,7 +80,8 @@ func InvalidBlockLVH(e error) [32]byte {
if e == nil {
return [32]byte{}
}
d, ok := e.(invalidBlockError)
var d invalidBlockError
ok := errors.As(e, &d)
if !ok {
return [32]byte{}
}
@@ -96,7 +94,8 @@ func InvalidBlockRoot(e error) [32]byte {
if e == nil {
return [32]byte{}
}
d, ok := e.(invalidBlockError)
var d invalidBlockError
ok := errors.As(e, &d)
if !ok {
return [32]byte{}
}
@@ -108,7 +107,8 @@ func InvalidAncestorRoots(e error) [][32]byte {
if e == nil {
return [][32]byte{}
}
d, ok := e.(invalidBlockError)
var d invalidBlockError
ok := errors.As(e, &d)
if !ok {
return [][32]byte{}
}

View File

@@ -24,6 +24,9 @@ func TestInvalidBlockRoot(t *testing.T) {
err := invalidBlock{error: ErrInvalidPayload, root: [32]byte{'a'}}
require.Equal(t, [32]byte{'a'}, InvalidBlockRoot(err))
require.DeepEqual(t, [][32]byte(nil), InvalidAncestorRoots(err))
newErr := errors.Wrap(err, "wrap me")
require.Equal(t, [32]byte{'a'}, InvalidBlockRoot(newErr))
}
func TestInvalidRoots(t *testing.T) {
@@ -33,4 +36,9 @@ func TestInvalidRoots(t *testing.T) {
require.Equal(t, true, IsInvalidBlock(err))
require.Equal(t, [32]byte{'a'}, InvalidBlockRoot(err))
require.DeepEqual(t, roots, InvalidAncestorRoots(err))
newErr := errors.Wrap(err, "wrap me")
require.Equal(t, true, IsInvalidBlock(err))
require.Equal(t, [32]byte{'a'}, InvalidBlockRoot(newErr))
require.DeepEqual(t, roots, InvalidAncestorRoots(newErr))
}

View File

@@ -0,0 +1,246 @@
package blockchain
import (
"bytes"
"context"
"fmt"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
"github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces"
types "github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
ethpbv1 "github.com/prysmaticlabs/prysm/v4/proto/eth/v1"
ethpbv2 "github.com/prysmaticlabs/prysm/v4/proto/eth/v2"
"github.com/prysmaticlabs/prysm/v4/proto/migration"
"github.com/prysmaticlabs/prysm/v4/time/slots"
)
const (
finalityBranchNumOfLeaves = 6
)
// 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 {
return &ethpbv2.LightClientFinalityUpdate{
AttestedHeader: update.AttestedHeader,
FinalizedHeader: update.FinalizedHeader,
FinalityBranch: update.FinalityBranch,
SyncAggregate: update.SyncAggregate,
SignatureSlot: update.SignatureSlot,
}
}
// 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 {
return &ethpbv2.LightClientOptimisticUpdate{
AttestedHeader: update.AttestedHeader,
SyncAggregate: update.SyncAggregate,
SignatureSlot: update.SignatureSlot,
}
}
func NewLightClientOptimisticUpdateFromBeaconState(
ctx context.Context,
state state.BeaconState,
block interfaces.ReadOnlySignedBeaconBlock,
attestedState state.BeaconState) (*ethpbv2.LightClientUpdate, error) {
// assert compute_epoch_at_slot(attested_state.slot) >= ALTAIR_FORK_EPOCH
attestedEpoch := slots.ToEpoch(attestedState.Slot())
if attestedEpoch < types.Epoch(params.BeaconConfig().AltairForkEpoch) {
return nil, fmt.Errorf("invalid attested epoch %d", attestedEpoch)
}
// assert sum(block.message.body.sync_aggregate.sync_committee_bits) >= MIN_SYNC_COMMITTEE_PARTICIPANTS
syncAggregate, err := block.Block().Body().SyncAggregate()
if err != nil {
return nil, fmt.Errorf("could not get sync aggregate %v", err)
}
if syncAggregate.SyncCommitteeBits.Count() < params.BeaconConfig().MinSyncCommitteeParticipants {
return nil, fmt.Errorf("invalid sync committee bits count %d", syncAggregate.SyncCommitteeBits.Count())
}
// assert state.slot == state.latest_block_header.slot
if state.Slot() != state.LatestBlockHeader().Slot {
return nil, fmt.Errorf("state slot %d not equal to latest block header slot %d", state.Slot(), state.LatestBlockHeader().Slot)
}
// assert hash_tree_root(header) == hash_tree_root(block.message)
header := state.LatestBlockHeader()
stateRoot, err := state.HashTreeRoot(ctx)
if err != nil {
return nil, fmt.Errorf("could not get state root %v", err)
}
header.StateRoot = stateRoot[:]
headerRoot, err := header.HashTreeRoot()
if err != nil {
return nil, fmt.Errorf("could not get header root %v", err)
}
blockRoot, err := block.Block().HashTreeRoot()
if err != nil {
return nil, fmt.Errorf("could not get block root %v", err)
}
if headerRoot != blockRoot {
return nil, fmt.Errorf("header root %#x not equal to block root %#x", headerRoot, blockRoot)
}
// 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)
}
// attested_header = attested_state.latest_block_header.copy()
attestedHeader := attestedState.LatestBlockHeader()
// attested_header.state_root = hash_tree_root(attested_state)
attestedStateRoot, err := attestedState.HashTreeRoot(ctx)
if err != nil {
return nil, fmt.Errorf("could not get attested state root %v", err)
}
attestedHeader.StateRoot = attestedStateRoot[:]
// assert hash_tree_root(attested_header) == block.message.parent_root
attestedHeaderRoot, err := attestedHeader.HashTreeRoot()
if err != nil {
return nil, fmt.Errorf("could not get attested header root %v", err)
}
if attestedHeaderRoot != block.Block().ParentRoot() {
return nil, fmt.Errorf("attested header root %#x not equal to block parent root %#x", attestedHeaderRoot, block.Block().ParentRoot())
}
// Return result
attestedHeaderResult := &ethpbv1.BeaconBlockHeader{
Slot: attestedHeader.Slot,
ProposerIndex: attestedHeader.ProposerIndex,
ParentRoot: attestedHeader.ParentRoot,
StateRoot: attestedHeader.StateRoot,
BodyRoot: attestedHeader.BodyRoot,
}
syncAggregateResult := &ethpbv1.SyncAggregate{
SyncCommitteeBits: syncAggregate.SyncCommitteeBits,
SyncCommitteeSignature: syncAggregate.SyncCommitteeSignature,
}
result := &ethpbv2.LightClientUpdate{
AttestedHeader: attestedHeaderResult,
SyncAggregate: syncAggregateResult,
SignatureSlot: block.Block().Slot(),
}
return result, nil
}
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
}
// Indicate finality whenever possible
var finalizedHeader *ethpbv1.BeaconBlockHeader
var finalityBranch [][]byte
if finalizedBlock != nil && !finalizedBlock.IsNil() {
if finalizedBlock.Block().Slot() != 0 {
tempFinalizedHeader, err := finalizedBlock.Header()
if err != nil {
return nil, fmt.Errorf("could not get finalized header %v", err)
}
finalizedHeader = migration.V1Alpha1SignedHeaderToV1(tempFinalizedHeader).GetMessage()
finalizedHeaderRoot, err := finalizedHeader.HashTreeRoot()
if err != nil {
return nil, fmt.Errorf("could not get finalized header root %v", err)
}
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)
}
finalizedHeader = &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, fmt.Errorf("could not get finalized root proof %v", bErr)
}
} else {
finalizedHeader = &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)
}
}
result.FinalizedHeader = finalizedHeader
result.FinalityBranch = finalityBranch
return result, 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

@@ -0,0 +1,160 @@
package blockchain
import (
"context"
"testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
"github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
v1 "github.com/prysmaticlabs/prysm/v4/proto/eth/v1"
ethpbv2 "github.com/prysmaticlabs/prysm/v4/proto/eth/v2"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v4/testing/require"
"github.com/prysmaticlabs/prysm/v4/testing/util"
)
type testlc struct {
t *testing.T
ctx context.Context
state state.BeaconState
block interfaces.ReadOnlySignedBeaconBlock
attestedState state.BeaconState
attestedHeader *ethpb.BeaconBlockHeader
}
func newTestLc(t *testing.T) *testlc {
return &testlc{t: t}
}
func (l *testlc) setupTest() *testlc {
ctx := context.Background()
slot := primitives.Slot(params.BeaconConfig().AltairForkEpoch * primitives.Epoch(params.BeaconConfig().SlotsPerEpoch)).Add(1)
attestedState, err := util.NewBeaconStateCapella()
require.NoError(l.t, err)
err = attestedState.SetSlot(slot)
require.NoError(l.t, err)
parent := util.NewBeaconBlockCapella()
parent.Block.Slot = slot
signedParent, err := blocks.NewSignedBeaconBlock(parent)
require.NoError(l.t, err)
parentHeader, err := signedParent.Header()
require.NoError(l.t, err)
attestedHeader := parentHeader.Header
err = attestedState.SetLatestBlockHeader(attestedHeader)
require.NoError(l.t, err)
attestedStateRoot, err := attestedState.HashTreeRoot(ctx)
require.NoError(l.t, err)
// get a new signed block so the root is updated with the new state root
parent.Block.StateRoot = attestedStateRoot[:]
signedParent, err = blocks.NewSignedBeaconBlock(parent)
require.NoError(l.t, err)
state, err := util.NewBeaconStateCapella()
require.NoError(l.t, err)
err = state.SetSlot(slot)
require.NoError(l.t, err)
parentRoot, err := signedParent.Block().HashTreeRoot()
require.NoError(l.t, err)
block := util.NewBeaconBlockCapella()
block.Block.Slot = slot
block.Block.ParentRoot = parentRoot[:]
for i := uint64(0); i < params.BeaconConfig().MinSyncCommitteeParticipants; i++ {
block.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true)
}
signedBlock, err := blocks.NewSignedBeaconBlock(block)
require.NoError(l.t, err)
h, err := signedBlock.Header()
require.NoError(l.t, err)
err = state.SetLatestBlockHeader(h.Header)
require.NoError(l.t, err)
stateRoot, err := state.HashTreeRoot(ctx)
require.NoError(l.t, err)
// get a new signed block so the root is updated with the new state root
block.Block.StateRoot = stateRoot[:]
signedBlock, err = blocks.NewSignedBeaconBlock(block)
require.NoError(l.t, err)
l.state = state
l.attestedState = attestedState
l.attestedHeader = attestedHeader
l.block = signedBlock
l.ctx = ctx
return l
}
func (l *testlc) checkAttestedHeader(update *ethpbv2.LightClientUpdate) {
require.Equal(l.t, l.attestedHeader.Slot, update.AttestedHeader.Slot, "Attested header slot is not equal")
require.Equal(l.t, l.attestedHeader.ProposerIndex, update.AttestedHeader.ProposerIndex, "Attested header proposer index is not equal")
require.DeepSSZEqual(l.t, l.attestedHeader.ParentRoot, update.AttestedHeader.ParentRoot, "Attested header parent root is not equal")
require.DeepSSZEqual(l.t, l.attestedHeader.BodyRoot, update.AttestedHeader.BodyRoot, "Attested header body root is not equal")
attestedStateRoot, err := l.attestedState.HashTreeRoot(l.ctx)
require.NoError(l.t, err)
require.DeepSSZEqual(l.t, attestedStateRoot[:], update.AttestedHeader.StateRoot, "Attested header state root is not equal")
}
func (l *testlc) checkSyncAggregate(update *ethpbv2.LightClientUpdate) {
syncAggregate, err := l.block.Block().Body().SyncAggregate()
require.NoError(l.t, err)
require.DeepSSZEqual(l.t, syncAggregate.SyncCommitteeBits, update.SyncAggregate.SyncCommitteeBits, "SyncAggregate bits is not equal")
require.DeepSSZEqual(l.t, syncAggregate.SyncCommitteeSignature, update.SyncAggregate.SyncCommitteeSignature, "SyncAggregate signature is not equal")
}
func TestLightClient_NewLightClientOptimisticUpdateFromBeaconState(t *testing.T) {
l := newTestLc(t).setupTest()
update, err := 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")
l.checkSyncAggregate(update)
l.checkAttestedHeader(update)
require.Equal(t, (*v1.BeaconBlockHeader)(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) {
l := newTestLc(t).setupTest()
update, err := 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")
require.Equal(t, primitives.Slot(0), update.FinalizedHeader.Slot, "Finalized header slot is not zero")
require.Equal(t, primitives.ValidatorIndex(0), update.FinalizedHeader.ProposerIndex, "Finalized header proposer index is not zero")
require.DeepSSZEqual(t, zeroHash, update.FinalizedHeader.ParentRoot, "Finalized header parent root is not zero")
require.DeepSSZEqual(t, zeroHash, update.FinalizedHeader.StateRoot, "Finalized header state root is not zero")
require.DeepSSZEqual(t, zeroHash, update.FinalizedHeader.BodyRoot, "Finalized header body root is not zero")
require.Equal(t, finalityBranchNumOfLeaves, len(update.FinalityBranch), "Invalid finality branch leaves")
for _, leaf := range update.FinalityBranch {
require.DeepSSZEqual(t, zeroHash, leaf, "Leaf is not zero")
}
}

View File

@@ -16,7 +16,7 @@ func TestReportEpochMetrics_BadHeadState(t *testing.T) {
require.NoError(t, err)
require.NoError(t, h.SetValidators(nil))
err = reportEpochMetrics(context.Background(), s, h)
require.ErrorContains(t, "failed to initialize precompute: nil validators in state", err)
require.ErrorContains(t, "failed to initialize precompute: state has nil validator slice", err)
}
func TestReportEpochMetrics_BadAttestation(t *testing.T) {

View File

@@ -649,11 +649,13 @@ func (s *Service) lateBlockTasks(ctx context.Context) {
return
}
s.headLock.RUnlock()
s.cfg.ForkChoiceStore.RLock()
_, err = s.notifyForkchoiceUpdate(ctx, &notifyForkchoiceUpdateArg{
headState: headState,
headRoot: headRoot,
headBlock: headBlock.Block(),
})
s.cfg.ForkChoiceStore.RUnlock()
if err != nil {
log.WithError(err).Debug("could not perform late block tasks: failed to update forkchoice with engine")
}

View File

@@ -1,7 +1,23 @@
package blockchain
import (
"context"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
)
// SendNewBlobEvent sends a message to the BlobNotifier channel that the blob
// for the blocroot `root` is ready in the database
func (s *Service) SendNewBlobEvent(root [32]byte, index uint64) {
func (s *Service) sendNewBlobEvent(root [32]byte, index uint64) {
s.blobNotifiers.forRoot(root) <- index
}
// ReceiveBlob saves the blob to database and sends the new event
func (s *Service) ReceiveBlob(ctx context.Context, b *ethpb.BlobSidecar) error {
if err := s.cfg.BeaconDB.SaveBlobSidecar(ctx, []*ethpb.BlobSidecar{b}); err != nil {
return err
}
s.sendNewBlobEvent([32]byte(b.BlockRoot), b.Index)
return nil
}

View File

@@ -3,6 +3,7 @@ package blockchain
import (
"bytes"
"context"
"time"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed"
@@ -21,7 +22,6 @@ import (
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1/attestation"
"github.com/prysmaticlabs/prysm/v4/runtime/version"
"github.com/prysmaticlabs/prysm/v4/time"
"github.com/prysmaticlabs/prysm/v4/time/slots"
"go.opencensus.io/trace"
"golang.org/x/sync/errgroup"
@@ -42,7 +42,7 @@ type BlockReceiver interface {
// BlobReceiver interface defines the methods of chain service for receiving new
// blobs
type BlobReceiver interface {
SendNewBlobEvent([32]byte, uint64)
ReceiveBlob(context.Context, *ethpb.BlobSidecar) error
}
// SlashingReceiver interface defines the methods of chain service for receiving validated slashing over the wire.

View File

@@ -606,10 +606,12 @@ func (s *ChainService) UnrealizedJustifiedPayloadBlockHash() [32]byte {
return [32]byte{}
}
// SendNewBlobEvent mocks the same method in the chain service
func (*ChainService) SendNewBlobEvent(_ [32]byte, _ uint64) {}
// BlockBeingSynced mocks the same method in the chain service
func (c *ChainService) BlockBeingSynced(root [32]byte) bool {
return root == c.SyncingRoot
}
// ReceiveBlob implements the same method in the chain service
func (*ChainService) ReceiveBlob(_ context.Context, _ *ethpb.BlobSidecar) error {
return nil
}

View File

@@ -31,7 +31,7 @@ func Test_BaseReward(t *testing.T) {
valIdx: 2,
st: genState(1),
want: 0,
errString: "index 2 out of range",
errString: "validator index 2 does not exist",
},
{
name: "active balance is 32eth",
@@ -89,7 +89,7 @@ func Test_BaseRewardWithTotalBalance(t *testing.T) {
valIdx: 2,
activeBalance: 1,
want: 0,
errString: "index 2 out of range",
errString: "validator index 2 does not exist",
},
{
name: "active balance is 1",

View File

@@ -51,6 +51,10 @@ func ProcessVoluntaryExits(
beaconState state.BeaconState,
exits []*ethpb.SignedVoluntaryExit,
) (state.BeaconState, error) {
// Avoid calculating the epoch churn if no exits exist.
if len(exits) == 0 {
return beaconState, nil
}
maxExitEpoch, churn := v.ValidatorsMaxExitEpochAndChurn(beaconState)
var exitEpoch primitives.Epoch
for idx, exit := range exits {

View File

@@ -82,7 +82,7 @@ func ProcessRandaoNoVerify(
for i, x := range blockRandaoReveal {
latestMixSlice[i] ^= x
}
if err := beaconState.UpdateRandaoMixesAtIndex(uint64(currentEpoch%latestMixesLength), latestMixSlice); err != nil {
if err := beaconState.UpdateRandaoMixesAtIndex(uint64(currentEpoch%latestMixesLength), [32]byte(latestMixSlice)); err != nil {
return nil, err
}
return beaconState, nil

View File

@@ -152,7 +152,7 @@ func TestProcessBLSToExecutionChange(t *testing.T) {
}
_, err = blocks.ProcessBLSToExecutionChange(st, signed)
require.ErrorContains(t, "out of range", err)
require.ErrorContains(t, "out of bounds", err)
})
t.Run("signature does not verify", func(t *testing.T) {

View File

@@ -137,9 +137,10 @@ func ProcessRegistryUpdates(ctx context.Context, state state.BeaconState) (state
return nil, errors.Wrap(err, "could not get active validator count")
}
churnLimit, err := helpers.ValidatorChurnLimit(activeValidatorCount)
if err != nil {
return nil, errors.Wrap(err, "could not get churn limit")
churnLimit := helpers.ValidatorActivationChurnLimit(activeValidatorCount)
if state.Version() >= version.Deneb {
churnLimit = helpers.ValidatorActivationChurnLimitDeneb(activeValidatorCount)
}
// Prevent churn limit cause index out of bound.
@@ -348,7 +349,7 @@ func ProcessRandaoMixesReset(state state.BeaconState) (state.BeaconState, error)
if err != nil {
return nil, err
}
if err := state.UpdateRandaoMixesAtIndex(uint64(nextEpoch%randaoMixLength), mix); err != nil {
if err := state.UpdateRandaoMixesAtIndex(uint64(nextEpoch%randaoMixLength), [32]byte(mix)); err != nil {
return nil, err
}

View File

@@ -311,8 +311,7 @@ func TestProcessRegistryUpdates_EligibleToActivate(t *testing.T) {
Slot: 5 * params.BeaconConfig().SlotsPerEpoch,
FinalizedCheckpoint: &ethpb.Checkpoint{Epoch: 6, Root: make([]byte, fieldparams.RootLength)},
}
limit, err := helpers.ValidatorChurnLimit(0)
require.NoError(t, err)
limit := helpers.ValidatorActivationChurnLimit(0)
for i := uint64(0); i < limit+10; i++ {
base.Validators = append(base.Validators, &ethpb.Validator{
ActivationEligibilityEpoch: params.BeaconConfig().FarFutureEpoch,
@@ -338,6 +337,42 @@ func TestProcessRegistryUpdates_EligibleToActivate(t *testing.T) {
}
}
func TestProcessRegistryUpdates_EligibleToActivate_Cancun(t *testing.T) {
base := &ethpb.BeaconStateDeneb{
Slot: 5 * params.BeaconConfig().SlotsPerEpoch,
FinalizedCheckpoint: &ethpb.Checkpoint{Epoch: 6, Root: make([]byte, fieldparams.RootLength)},
}
cfg := params.BeaconConfig()
cfg.MinPerEpochChurnLimit = 10
cfg.ChurnLimitQuotient = 1
params.OverrideBeaconConfig(cfg)
for i := uint64(0); i < 10; i++ {
base.Validators = append(base.Validators, &ethpb.Validator{
ActivationEligibilityEpoch: params.BeaconConfig().FarFutureEpoch,
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
ActivationEpoch: params.BeaconConfig().FarFutureEpoch,
})
}
beaconState, err := state_native.InitializeFromProtoDeneb(base)
require.NoError(t, err)
currentEpoch := time.CurrentEpoch(beaconState)
newState, err := epoch.ProcessRegistryUpdates(context.Background(), beaconState)
require.NoError(t, err)
for i, validator := range newState.Validators() {
assert.Equal(t, currentEpoch+1, validator.ActivationEligibilityEpoch, "Could not update registry %d, unexpected activation eligibility epoch", i)
// Note: In Deneb, only validators indices before `MaxPerEpochActivationChurnLimit` should be activated.
if uint64(i) < params.BeaconConfig().MaxPerEpochActivationChurnLimit && validator.ActivationEpoch != helpers.ActivationExitEpoch(currentEpoch) {
t.Errorf("Could not update registry %d, validators failed to activate: wanted activation epoch %d, got %d",
i, helpers.ActivationExitEpoch(currentEpoch), validator.ActivationEpoch)
}
if uint64(i) >= params.BeaconConfig().MaxPerEpochActivationChurnLimit && validator.ActivationEpoch != params.BeaconConfig().FarFutureEpoch {
t.Errorf("Could not update registry %d, validators should not have been activated, wanted activation epoch: %d, got %d",
i, params.BeaconConfig().FarFutureEpoch, validator.ActivationEpoch)
}
}
}
func TestProcessRegistryUpdates_ActivationCompletes(t *testing.T) {
base := &ethpb.BeaconState{
Slot: 5 * params.BeaconConfig().SlotsPerEpoch,

View File

@@ -99,7 +99,7 @@ func TestIsCurrentEpochSyncCommittee_DoesNotExist(t *testing.T) {
require.NoError(t, state.SetNextSyncCommittee(syncCommittee))
ok, err := IsCurrentPeriodSyncCommittee(state, 12390192)
require.ErrorContains(t, "index 12390192 out of range", err)
require.ErrorContains(t, "validator index 12390192 does not exist", err)
require.Equal(t, false, ok)
}
@@ -182,7 +182,7 @@ func TestIsNextEpochSyncCommittee_DoesNotExist(t *testing.T) {
require.NoError(t, state.SetNextSyncCommittee(syncCommittee))
ok, err := IsNextPeriodSyncCommittee(state, 120391029)
require.ErrorContains(t, "index 120391029 out of range", err)
require.ErrorContains(t, "validator index 120391029 does not exist", err)
require.Equal(t, false, ok)
}
@@ -282,7 +282,7 @@ func TestCurrentEpochSyncSubcommitteeIndices_DoesNotExist(t *testing.T) {
require.NoError(t, state.SetNextSyncCommittee(syncCommittee))
index, err := CurrentPeriodSyncSubcommitteeIndices(state, 129301923)
require.ErrorContains(t, "index 129301923 out of range", err)
require.ErrorContains(t, "validator index 129301923 does not exist", err)
require.DeepEqual(t, []primitives.CommitteeIndex(nil), index)
}
@@ -367,7 +367,7 @@ func TestNextEpochSyncSubcommitteeIndices_DoesNotExist(t *testing.T) {
require.NoError(t, state.SetNextSyncCommittee(syncCommittee))
index, err := NextPeriodSyncSubcommitteeIndices(state, 21093019)
require.ErrorContains(t, "index 21093019 out of range", err)
require.ErrorContains(t, "validator index 21093019 does not exist", err)
require.DeepEqual(t, []primitives.CommitteeIndex(nil), index)
}

View File

@@ -206,10 +206,7 @@ func ActivationExitEpoch(epoch primitives.Epoch) primitives.Epoch {
return epoch + 1 + params.BeaconConfig().MaxSeedLookahead
}
// ValidatorChurnLimit returns the number of validators that are allowed to
// enter and exit validator pool for an epoch.
//
// Spec pseudocode definition:
// calculateChurnLimit based on the formula in the spec.
//
// def get_validator_churn_limit(state: BeaconState) -> uint64:
// """
@@ -217,12 +214,32 @@ func ActivationExitEpoch(epoch primitives.Epoch) primitives.Epoch {
// """
// active_validator_indices = get_active_validator_indices(state, get_current_epoch(state))
// return max(MIN_PER_EPOCH_CHURN_LIMIT, uint64(len(active_validator_indices)) // CHURN_LIMIT_QUOTIENT)
func ValidatorChurnLimit(activeValidatorCount uint64) (uint64, error) {
func calculateChurnLimit(activeValidatorCount uint64) uint64 {
churnLimit := activeValidatorCount / params.BeaconConfig().ChurnLimitQuotient
if churnLimit < params.BeaconConfig().MinPerEpochChurnLimit {
churnLimit = params.BeaconConfig().MinPerEpochChurnLimit
return params.BeaconConfig().MinPerEpochChurnLimit
}
return churnLimit, nil
return churnLimit
}
// ValidatorActivationChurnLimit returns the maximum number of validators that can be activated in a slot.
func ValidatorActivationChurnLimit(activeValidatorCount uint64) uint64 {
return calculateChurnLimit(activeValidatorCount)
}
// ValidatorExitChurnLimit returns the maximum number of validators that can be exited in a slot.
func ValidatorExitChurnLimit(activeValidatorCount uint64) uint64 {
return calculateChurnLimit(activeValidatorCount)
}
// ValidatorActivationChurnLimitDeneb returns the maximum number of validators that can be activated in a slot post Deneb.
func ValidatorActivationChurnLimitDeneb(activeValidatorCount uint64) uint64 {
limit := calculateChurnLimit(activeValidatorCount)
// New in Deneb.
if limit > params.BeaconConfig().MaxPerEpochActivationChurnLimit {
return params.BeaconConfig().MaxPerEpochActivationChurnLimit
}
return limit
}
// BeaconProposerIndex returns proposer index of a current slot.

View File

@@ -367,9 +367,50 @@ func TestChurnLimit_OK(t *testing.T) {
require.NoError(t, err)
validatorCount, err := ActiveValidatorCount(context.Background(), beaconState, time.CurrentEpoch(beaconState))
require.NoError(t, err)
resultChurn, err := ValidatorChurnLimit(validatorCount)
resultChurn := ValidatorActivationChurnLimit(validatorCount)
assert.Equal(t, test.wantedChurn, resultChurn, "ValidatorActivationChurnLimit(%d)", test.validatorCount)
}
}
func TestChurnLimitDeneb_OK(t *testing.T) {
tests := []struct {
validatorCount int
wantedChurn uint64
}{
{1000, 4},
{100000, 4},
{1000000, params.BeaconConfig().MaxPerEpochActivationChurnLimit},
{2000000, params.BeaconConfig().MaxPerEpochActivationChurnLimit},
}
defer ClearCache()
for _, test := range tests {
ClearCache()
// Create validators
validators := make([]*ethpb.Validator, test.validatorCount)
for i := range validators {
validators[i] = &ethpb.Validator{
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
}
}
// Initialize beacon state
beaconState, err := state_native.InitializeFromProtoPhase0(&ethpb.BeaconState{
Slot: 1,
Validators: validators,
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
})
require.NoError(t, err)
assert.Equal(t, test.wantedChurn, resultChurn, "ValidatorChurnLimit(%d)", test.validatorCount)
// Get active validator count
validatorCount, err := ActiveValidatorCount(context.Background(), beaconState, time.CurrentEpoch(beaconState))
require.NoError(t, err)
// Test churn limit calculation
resultChurn := ValidatorActivationChurnLimitDeneb(validatorCount)
assert.Equal(t, test.wantedChurn, resultChurn)
}
}

View File

@@ -80,10 +80,7 @@ func ComputeWeakSubjectivityPeriod(ctx context.Context, st state.ReadOnlyBeaconS
T := cfg.MaxEffectiveBalance / cfg.GweiPerEth
// Validator churn limit.
delta, err := ValidatorChurnLimit(N)
if err != nil {
return 0, fmt.Errorf("cannot obtain active validator churn limit: %w", err)
}
delta := ValidatorExitChurnLimit(N)
// Balance top-ups.
Delta := uint64(cfg.SlotsPerEpoch.Mul(cfg.MaxDeposits))

View File

@@ -9,6 +9,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
state_native "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stateutil"
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
"github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/container/trie"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
@@ -221,6 +222,18 @@ func OptimizedGenesisBeaconState(genesisTime uint64, preState state.BeaconState,
// EmptyGenesisState returns an empty beacon state object.
func EmptyGenesisState() (state.BeaconState, error) {
blockRoots := make([][]byte, fieldparams.BlockRootsLength)
for i := range blockRoots {
blockRoots[i] = make([]byte, fieldparams.RootLength)
}
stateRoots := make([][]byte, fieldparams.StateRootsLength)
for i := range stateRoots {
stateRoots[i] = make([]byte, fieldparams.RootLength)
}
mixes := make([][]byte, fieldparams.RandaoMixesLength)
for i := range mixes {
mixes[i] = make([]byte, fieldparams.RootLength)
}
st := &ethpb.BeaconState{
// Misc fields.
Slot: 0,
@@ -229,6 +242,9 @@ func EmptyGenesisState() (state.BeaconState, error) {
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
Epoch: 0,
},
BlockRoots: blockRoots,
StateRoots: stateRoots,
RandaoMixes: mixes,
// Validator registry fields.
Validators: []*ethpb.Validator{},
Balances: []uint64{},

View File

@@ -82,10 +82,7 @@ func InitiateValidatorExit(ctx context.Context, s state.BeaconState, idx primiti
if err != nil {
return nil, 0, errors.Wrap(err, "could not get active validator count")
}
currentChurn, err := helpers.ValidatorChurnLimit(activeValidatorCount)
if err != nil {
return nil, 0, errors.Wrap(err, "could not get churn limit")
}
currentChurn := helpers.ValidatorExitChurnLimit(activeValidatorCount)
if churn >= currentChurn {
exitQueueEpoch, err = exitQueueEpoch.SafeAdd(1)
@@ -235,10 +232,7 @@ func ExitedValidatorIndices(epoch primitives.Epoch, validators []*ethpb.Validato
exitQueueChurn++
}
}
churn, err := helpers.ValidatorChurnLimit(activeValidatorCount)
if err != nil {
return nil, errors.Wrap(err, "could not get churn limit")
}
churn := helpers.ValidatorExitChurnLimit(activeValidatorCount)
if churn < exitQueueChurn {
exitQueueEpoch++
}
@@ -276,10 +270,7 @@ func EjectedValidatorIndices(epoch primitives.Epoch, validators []*ethpb.Validat
exitQueueChurn++
}
}
churn, err := helpers.ValidatorChurnLimit(activeValidatorCount)
if err != nil {
return nil, errors.Wrap(err, "could not get churn limit")
}
churn := helpers.ValidatorExitChurnLimit(activeValidatorCount)
if churn < exitQueueChurn {
exitQueueEpoch++
}

View File

@@ -13,10 +13,7 @@ func (f *ForkChoice) LastRoot(epoch primitives.Epoch) [32]byte {
if err != nil {
return [32]byte{}
}
if headEpoch < epoch {
return [32]byte{}
}
if headEpoch == epoch {
if headEpoch <= epoch {
return head.root
}
for head != nil && head.slot > epochEnd {

View File

@@ -35,5 +35,5 @@ func TestLastRoot(t *testing.T) {
require.Equal(t, [32]byte{'6'}, f.store.headNode.root)
require.Equal(t, [32]byte{'2'}, f.LastRoot(0))
require.Equal(t, [32]byte{'6'}, f.LastRoot(1))
require.Equal(t, [32]byte{}, f.LastRoot(2))
require.Equal(t, [32]byte{'6'}, f.LastRoot(2))
}

View File

@@ -49,6 +49,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
slot := primitives.Slot(1)
driftGenesisTime(f, slot, 0)
newRoot := indexToHash(1)
f.store.proposerBoostRoot = [32]byte{}
state, blkRoot, err := prepareForkchoiceState(
ctx,
slot,
@@ -74,6 +75,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
slot = primitives.Slot(2)
driftGenesisTime(f, slot, 0)
newRoot = indexToHash(2)
f.store.proposerBoostRoot = [32]byte{}
state, blkRoot, err = prepareForkchoiceState(
ctx,
slot,
@@ -101,6 +103,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
slot = primitives.Slot(3)
driftGenesisTime(f, slot, 0)
newRoot = indexToHash(3)
f.store.proposerBoostRoot = [32]byte{}
state, blkRoot, err = prepareForkchoiceState(
ctx,
slot,
@@ -129,6 +132,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
slot = primitives.Slot(4)
driftGenesisTime(f, slot, 0)
newRoot = indexToHash(4)
f.store.proposerBoostRoot = [32]byte{}
state, blkRoot, err = prepareForkchoiceState(
ctx,
slot,
@@ -335,6 +339,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
cSlot := primitives.Slot(2)
driftGenesisTime(f, cSlot, 0)
c := indexToHash(2)
f.store.proposerBoostRoot = [32]byte{}
state, blkRoot, err := prepareForkchoiceState(
ctx,
cSlot,
@@ -354,6 +359,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
bSlot := primitives.Slot(1)
b := indexToHash(1)
f.store.proposerBoostRoot = [32]byte{}
state, blkRoot, err = prepareForkchoiceState(
ctx,
bSlot,
@@ -378,6 +384,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
// A block D, building on B, is received at slot N+3. It should not be able to win without boosting.
dSlot := primitives.Slot(3)
d := indexToHash(3)
f.store.proposerBoostRoot = [32]byte{}
state, blkRoot, err = prepareForkchoiceState(
ctx,
dSlot,
@@ -398,6 +405,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
// If the same block arrives with boosting then it becomes head:
driftGenesisTime(f, dSlot, 0)
d2 := indexToHash(30)
f.store.proposerBoostRoot = [32]byte{}
state, blkRoot, err = prepareForkchoiceState(
ctx,
dSlot,

View File

@@ -109,7 +109,8 @@ func (s *Store) insert(ctx context.Context,
secondsIntoSlot := (timeNow - s.genesisTime) % params.BeaconConfig().SecondsPerSlot
currentSlot := slots.CurrentSlot(s.genesisTime)
boostThreshold := params.BeaconConfig().SecondsPerSlot / params.BeaconConfig().IntervalsPerSlot
if currentSlot == slot && secondsIntoSlot < boostThreshold {
isFirstBlock := s.proposerBoostRoot == [32]byte{}
if currentSlot == slot && secondsIntoSlot < boostThreshold && isFirstBlock {
s.proposerBoostRoot = root
}

View File

@@ -8,6 +8,7 @@ go_library(
"node.go",
"options.go",
"prometheus.go",
"router.go",
],
importpath = "github.com/prysmaticlabs/prysm/v4/beacon-chain/node",
visibility = [
@@ -40,6 +41,7 @@ go_library(
"//beacon-chain/p2p:go_default_library",
"//beacon-chain/rpc:go_default_library",
"//beacon-chain/rpc/apimiddleware:go_default_library",
"//beacon-chain/rpc/eth/helpers:go_default_library",
"//beacon-chain/slasher:go_default_library",
"//beacon-chain/startup:go_default_library",
"//beacon-chain/state:go_default_library",

View File

@@ -271,6 +271,7 @@ func New(cliCtx *cli.Context, opts ...Option) (*BeaconNode, error) {
log.Debugln("Registering RPC Service")
router := mux.NewRouter()
router.Use(middleware)
if err := beacon.registerRPCService(router); err != nil {
return nil, err
}

View File

@@ -0,0 +1,17 @@
package node
import (
"net/http"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/helpers"
)
func middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query()
helpers.NormalizeQueryValues(query)
r.URL.RawQuery = query.Encode()
next.ServeHTTP(w, r)
})
}

View File

@@ -33,6 +33,7 @@ go_test(
srcs = [
"custom_handlers_test.go",
"custom_hooks_test.go",
"endpoint_factory_test.go",
"structs_marshalling_test.go",
],
embed = [":go_default_library"],

View File

@@ -19,7 +19,6 @@ func (_ *BeaconEndpointFactory) Paths() []string {
"/eth/v1/beacon/states/{state_id}/root",
"/eth/v1/beacon/states/{state_id}/sync_committees",
"/eth/v1/beacon/states/{state_id}/randao",
"/eth/v1/beacon/blinded_blocks",
"/eth/v1/beacon/blocks/{block_id}",
"/eth/v2/beacon/blocks/{block_id}",
"/eth/v1/beacon/blocks/{block_id}/attestations",

View File

@@ -0,0 +1,17 @@
package apimiddleware_test
import (
"testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/apimiddleware"
"github.com/prysmaticlabs/prysm/v4/testing/require"
)
func TestBeaconEndpointFactory_AllPathsRegistered(t *testing.T) {
f := &apimiddleware.BeaconEndpointFactory{}
for _, p := range f.Paths() {
_, err := f.Create(p)
require.NoError(t, err, "failed to register %s", p)
}
}

View File

@@ -459,12 +459,12 @@ func (s *Service) GetAttestationData(
// SubmitSyncMessage submits the sync committee message to the network.
// It also saves the sync committee message into the pending pool for block inclusion.
func (s *Service) SubmitSyncMessage(ctx context.Context, msg *ethpb.SyncCommitteeMessage) error {
func (s *Service) SubmitSyncMessage(ctx context.Context, msg *ethpb.SyncCommitteeMessage) *RpcError {
errs, ctx := errgroup.WithContext(ctx)
headSyncCommitteeIndices, err := s.HeadFetcher.HeadSyncCommitteeIndices(ctx, msg.ValidatorIndex, msg.Slot)
if err != nil {
return err
return &RpcError{Reason: Internal, Err: errors.Wrap(err, "could not get head sync committee indices")}
}
// Broadcasting and saving message into the pool in parallel. As one fail should not affect another.
// This broadcasts for all subnets.
@@ -477,9 +477,12 @@ func (s *Service) SubmitSyncMessage(ctx context.Context, msg *ethpb.SyncCommitte
}
if err := s.SyncCommitteePool.SaveSyncCommitteeMessage(msg); err != nil {
return err
return &RpcError{Reason: Internal, Err: errors.Wrap(err, "could not save sync committee message")}
}
// Wait for p2p broadcast to complete and return the first error (if any)
return errs.Wait()
if err = errs.Wait(); err != nil {
return &RpcError{Reason: Internal, Err: errors.Wrap(err, "could not broadcast sync committee message")}
}
return nil
}

View File

@@ -64,7 +64,6 @@ go_library(
"//runtime/version:go_default_library",
"//time/slots:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
"@com_github_go_playground_validator_v10//:go_default_library",
"@com_github_gorilla_mux//:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",

View File

@@ -5,6 +5,7 @@ import (
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v4/api"
rpchelpers "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/helpers"
consensus_types "github.com/prysmaticlabs/prysm/v4/consensus-types"
"github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces"
ethpbv1 "github.com/prysmaticlabs/prysm/v4/proto/eth/v1"
@@ -24,7 +25,7 @@ func (bs *Server) GetBlindedBlock(ctx context.Context, req *ethpbv1.BlockRequest
defer span.End()
blk, err := bs.Blocker.Block(ctx, req.BlockId)
err = handleGetBlockError(blk, err)
err = rpchelpers.HandleGetBlockError(blk, err)
if err != nil {
return nil, err
}
@@ -90,7 +91,7 @@ func (bs *Server) GetBlindedBlockSSZ(ctx context.Context, req *ethpbv1.BlockRequ
defer span.End()
blk, err := bs.Blocker.Block(ctx, req.BlockId)
err = handleGetBlockError(blk, err)
err = rpchelpers.HandleGetBlockError(blk, err)
if err != nil {
return nil, err
}

View File

@@ -9,10 +9,8 @@ import (
"github.com/prysmaticlabs/prysm/v4/api"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/helpers"
rpchelpers "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/helpers"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup"
"github.com/prysmaticlabs/prysm/v4/config/params"
consensus_types "github.com/prysmaticlabs/prysm/v4/consensus-types"
"github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces"
ethpbv1 "github.com/prysmaticlabs/prysm/v4/proto/eth/v1"
ethpbv2 "github.com/prysmaticlabs/prysm/v4/proto/eth/v2"
@@ -79,7 +77,7 @@ func (bs *Server) GetBlock(ctx context.Context, req *ethpbv1.BlockRequest) (*eth
defer span.End()
blk, err := bs.Blocker.Block(ctx, req.BlockId)
err = handleGetBlockError(blk, err)
err = rpchelpers.HandleGetBlockError(blk, err)
if err != nil {
return nil, err
}
@@ -103,7 +101,7 @@ func (bs *Server) GetBlockSSZ(ctx context.Context, req *ethpbv1.BlockRequest) (*
defer span.End()
blk, err := bs.Blocker.Block(ctx, req.BlockId)
err = handleGetBlockError(blk, err)
err = rpchelpers.HandleGetBlockError(blk, err)
if err != nil {
return nil, err
}
@@ -125,7 +123,7 @@ func (bs *Server) GetBlockV2(ctx context.Context, req *ethpbv2.BlockRequestV2) (
defer span.End()
blk, err := bs.Blocker.Block(ctx, req.BlockId)
err = handleGetBlockError(blk, err)
err = rpchelpers.HandleGetBlockError(blk, err)
if err != nil {
return nil, err
}
@@ -193,7 +191,7 @@ func (bs *Server) GetBlockSSZV2(ctx context.Context, req *ethpbv2.BlockRequestV2
defer span.End()
blk, err := bs.Blocker.Block(ctx, req.BlockId)
err = handleGetBlockError(blk, err)
err = rpchelpers.HandleGetBlockError(blk, err)
if err != nil {
return nil, err
}
@@ -258,7 +256,7 @@ func (bs *Server) ListBlockAttestations(ctx context.Context, req *ethpbv1.BlockR
defer span.End()
blk, err := bs.Blocker.Block(ctx, req.BlockId)
err = handleGetBlockError(blk, err)
err = rpchelpers.HandleGetBlockError(blk, err)
if err != nil {
return nil, err
}
@@ -284,19 +282,6 @@ func (bs *Server) ListBlockAttestations(ctx context.Context, req *ethpbv1.BlockR
}, nil
}
func handleGetBlockError(blk interfaces.ReadOnlySignedBeaconBlock, err error) error {
if invalidBlockIdErr, ok := err.(*lookup.BlockIdParseError); ok {
return status.Errorf(codes.InvalidArgument, "Invalid block ID: %v", invalidBlockIdErr)
}
if err != nil {
return status.Errorf(codes.Internal, "Could not get block from block ID: %v", err)
}
if err := blocks.BeaconBlockIsNil(blk); err != nil {
return status.Errorf(codes.NotFound, "Could not find requested block: %v", err)
}
return nil
}
func getBlockPhase0(blk interfaces.ReadOnlySignedBeaconBlock) (*ethpbv2.BlockResponseV2, error) {
phase0Blk, err := blk.PbPhase0Block()
if err != nil {

View File

@@ -141,7 +141,7 @@ func TestGetSpec(t *testing.T) {
resp, err := server.GetSpec(context.Background(), &emptypb.Empty{})
require.NoError(t, err)
assert.Equal(t, 111, len(resp.Data))
assert.Equal(t, 112, len(resp.Data))
for k, v := range resp.Data {
switch k {
case "CONFIG_NAME":
@@ -380,6 +380,8 @@ func TestGetSpec(t *testing.T) {
assert.Equal(t, "20", v)
case "REORG_PARENT_WEIGHT_THRESHOLD":
assert.Equal(t, "160", v)
case "MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT":
assert.Equal(t, "8", v)
case "SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY":
default:
t.Errorf("Incorrect key: %s", k)

View File

@@ -2,20 +2,21 @@ package beacon
import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"strconv"
"strings"
"github.com/go-playground/validator/v10"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/operation"
corehelpers "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/transition"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/core"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/shared"
state_native "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native"
consensus_types "github.com/prysmaticlabs/prysm/v4/consensus-types"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v4/crypto/bls"
http2 "github.com/prysmaticlabs/prysm/v4/network/http"
@@ -89,11 +90,6 @@ func (s *Server) SubmitAttestations(w http.ResponseWriter, r *http.Request) {
http2.HandleError(w, "No data submitted", http.StatusBadRequest)
return
}
validate := validator.New()
if err := validate.Struct(req); err != nil {
http2.HandleError(w, err.Error(), http.StatusBadRequest)
return
}
var validAttestations []*ethpbalpha.Attestation
var attFailures []*shared.IndexedVerificationFailure
@@ -209,11 +205,6 @@ func (s *Server) SubmitVoluntaryExit(w http.ResponseWriter, r *http.Request) {
http2.HandleError(w, "Could not decode request body: "+err.Error(), http.StatusBadRequest)
return
}
validate := validator.New()
if err := validate.Struct(req); err != nil {
http2.HandleError(w, err.Error(), http.StatusBadRequest)
return
}
exit, err := req.ToConsensus()
if err != nil {
@@ -238,8 +229,8 @@ func (s *Server) SubmitVoluntaryExit(w http.ResponseWriter, r *http.Request) {
}
val, err := headState.ValidatorAtIndexReadOnly(exit.Exit.ValidatorIndex)
if err != nil {
if outOfRangeErr, ok := err.(*state_native.ValidatorIndexOutOfRangeError); ok {
http2.HandleError(w, "Could not get exiting validator: "+outOfRangeErr.Error(), http.StatusBadRequest)
if errors.Is(err, consensus_types.ErrOutOfBounds) {
http2.HandleError(w, "Could not get validator: "+err.Error(), http.StatusBadRequest)
return
}
http2.HandleError(w, "Could not get validator: "+err.Error(), http.StatusInternalServerError)
@@ -292,8 +283,8 @@ func (s *Server) SubmitSyncCommitteeSignatures(w http.ResponseWriter, r *http.Re
}
for _, msg := range validMessages {
if err = s.CoreService.SubmitSyncMessage(ctx, msg); err != nil {
http2.HandleError(w, "Could not submit message: "+err.Error(), http.StatusInternalServerError)
if rpcerr := s.CoreService.SubmitSyncMessage(ctx, msg); rpcerr != nil {
http2.HandleError(w, "Could not submit message: "+rpcerr.Err.Error(), core.ErrorReasonToHTTP(rpcerr.Reason))
return
}
}

View File

@@ -485,7 +485,7 @@ func TestSubmitVoluntaryExit(t *testing.T) {
e := &http2.DefaultErrorJson{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), e))
assert.Equal(t, http.StatusBadRequest, e.Code)
assert.Equal(t, true, strings.Contains(e.Message, "Could not get exiting validator"))
assert.Equal(t, true, strings.Contains(e.Message, "Could not get validator"))
})
}

View File

@@ -108,8 +108,8 @@ func TestGetStateRoot(t *testing.T) {
}
func TestGetRandao(t *testing.T) {
mixCurrent := bytesutil.PadTo([]byte("current"), 32)
mixOld := bytesutil.PadTo([]byte("old"), 32)
mixCurrent := bytesutil.ToBytes32([]byte("current"))
mixOld := bytesutil.ToBytes32([]byte("old"))
epochCurrent := primitives.Epoch(100000)
epochOld := 100000 - params.BeaconConfig().EpochsPerHistoricalVector + 1
@@ -125,7 +125,7 @@ func TestGetRandao(t *testing.T) {
headSt, err := util.NewBeaconState()
require.NoError(t, err)
require.NoError(t, headSt.SetSlot(params.BeaconConfig().SlotsPerEpoch))
headRandao := bytesutil.PadTo([]byte("head"), 32)
headRandao := bytesutil.ToBytes32([]byte("head"))
require.NoError(t, headSt.UpdateRandaoMixesAtIndex(uint64(headEpoch), headRandao))
db := dbTest.SetupDB(t)
@@ -143,17 +143,17 @@ func TestGetRandao(t *testing.T) {
t.Run("no epoch requested", func(t *testing.T) {
resp, err := server.GetRandao(ctx, &eth2.RandaoRequest{StateId: []byte("head")})
require.NoError(t, err)
assert.DeepEqual(t, mixCurrent, resp.Data.Randao)
assert.DeepEqual(t, mixCurrent[:], resp.Data.Randao)
})
t.Run("current epoch requested", func(t *testing.T) {
resp, err := server.GetRandao(ctx, &eth2.RandaoRequest{StateId: []byte("head"), Epoch: &epochCurrent})
require.NoError(t, err)
assert.DeepEqual(t, mixCurrent, resp.Data.Randao)
assert.DeepEqual(t, mixCurrent[:], resp.Data.Randao)
})
t.Run("old epoch requested", func(t *testing.T) {
resp, err := server.GetRandao(ctx, &eth2.RandaoRequest{StateId: []byte("head"), Epoch: &epochOld})
require.NoError(t, err)
assert.DeepEqual(t, mixOld, resp.Data.Randao)
assert.DeepEqual(t, mixOld[:], resp.Data.Randao)
})
t.Run("head state below `EpochsPerHistoricalVector`", func(t *testing.T) {
server.Stater = &testutil.MockStater{
@@ -161,7 +161,7 @@ func TestGetRandao(t *testing.T) {
}
resp, err := server.GetRandao(ctx, &eth2.RandaoRequest{StateId: []byte("head")})
require.NoError(t, err)
assert.DeepEqual(t, headRandao, resp.Data.Randao)
assert.DeepEqual(t, headRandao[:], resp.Data.Randao)
})
t.Run("epoch too old", func(t *testing.T) {
epochTooOld := primitives.Epoch(100000 - st.RandaoMixesLength())

View File

@@ -12,7 +12,6 @@ go_library(
deps = [
"//beacon-chain/blockchain:go_default_library",
"//beacon-chain/db:go_default_library",
"//beacon-chain/rpc/eth/helpers:go_default_library",
"//beacon-chain/rpc/lookup:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",

View File

@@ -8,7 +8,6 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/helpers"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup"
field_params "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
"github.com/prysmaticlabs/prysm/v4/config/params"
@@ -122,9 +121,7 @@ func (s *Server) Blobs(w http.ResponseWriter, r *http.Request) {
// parseIndices filters out invalid and duplicate blob indices
func parseIndices(url *url.URL) []uint64 {
query := url.Query()
helpers.NormalizeQueryValues(query)
rawIndices := query["indices"]
rawIndices := url.Query()["indices"]
indices := make([]uint64, 0, field_params.MaxBlobsPerBlock)
loop:
for _, raw := range rawIndices {

View File

@@ -23,7 +23,7 @@ import (
)
func TestParseIndices(t *testing.T) {
assert.DeepEqual(t, []uint64{1, 2, 3}, parseIndices(&url.URL{RawQuery: "indices=1,2,foo,1&indices=3,1&bar=bar"}))
assert.DeepEqual(t, []uint64{1, 2, 3}, parseIndices(&url.URL{RawQuery: "indices=1&indices=2&indices=foo&indices=1&indices=3&bar=bar"}))
}
func TestBlobs(t *testing.T) {

View File

@@ -20,10 +20,13 @@ go_library(
"//beacon-chain/state/stategen:go_default_library",
"//beacon-chain/sync:go_default_library",
"//config/params:go_default_library",
"//consensus-types/blocks:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//consensus-types/primitives:go_default_library",
"//consensus-types/validator:go_default_library",
"//encoding/bytesutil: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",
"@org_golang_google_grpc//codes:go_default_library",
"@org_golang_google_grpc//status:go_default_library",
@@ -60,6 +63,7 @@ go_test(
"//testing/assert:go_default_library",
"//testing/require:go_default_library",
"//testing/util:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
"@com_github_grpc_ecosystem_grpc_gateway_v2//runtime:go_default_library",
"@org_golang_google_grpc//:go_default_library",
],

View File

@@ -5,6 +5,8 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen"
"github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
@@ -34,3 +36,16 @@ type SingleIndexedVerificationFailure struct {
Index int `json:"index"`
Message string `json:"message"`
}
func HandleGetBlockError(blk interfaces.ReadOnlySignedBeaconBlock, err error) error {
if invalidBlockIdErr, ok := err.(*lookup.BlockIdParseError); ok {
return status.Errorf(codes.InvalidArgument, "Invalid block ID: %v", invalidBlockIdErr)
}
if err != nil {
return status.Errorf(codes.Internal, "Could not get block from block ID: %v", err)
}
if err := blocks.BeaconBlockIsNil(blk); err != nil {
return status.Errorf(codes.NotFound, "Could not find requested block: %v", err)
}
return nil
}

View File

@@ -6,6 +6,7 @@ import (
"strconv"
"strings"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v4/api/grpc"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain"
@@ -95,7 +96,13 @@ func IsOptimistic(
}
return optimisticModeFetcher.IsOptimisticForRoot(ctx, bytesutil.ToBytes32(jcp.Root))
default:
if len(stateId) == 32 {
if len(stateIdString) >= 2 && stateIdString[:2] == "0x" {
id, err := hexutil.Decode(stateIdString)
if err != nil {
return false, err
}
return isStateRootOptimistic(ctx, id, optimisticModeFetcher, stateFetcher, chainInfo, database)
} else if len(stateId) == 32 {
return isStateRootOptimistic(ctx, stateId, optimisticModeFetcher, stateFetcher, chainInfo, database)
} else {
optimistic, err := optimisticModeFetcher.IsOptimistic(ctx)

View File

@@ -6,6 +6,7 @@ import (
"strings"
"testing"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
grpcutil "github.com/prysmaticlabs/prysm/v4/api/grpc"
chainmock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing"
@@ -204,6 +205,78 @@ func TestIsOptimistic(t *testing.T) {
assert.Equal(t, true, o)
})
})
t.Run("hex", func(t *testing.T) {
t.Run("is head and head is optimistic", func(t *testing.T) {
st, err := util.NewBeaconState()
require.NoError(t, err)
cs := &chainmock.ChainService{Optimistic: true}
mf := &testutil.MockStater{BeaconState: st}
o, err := IsOptimistic(ctx, []byte(hexutil.Encode(bytesutil.PadTo([]byte("root"), 32))), cs, mf, cs, nil)
require.NoError(t, err)
assert.Equal(t, true, o)
})
t.Run("is head and head is not optimistic", func(t *testing.T) {
st, err := util.NewBeaconState()
require.NoError(t, err)
cs := &chainmock.ChainService{Optimistic: false}
mf := &testutil.MockStater{BeaconState: st}
o, err := IsOptimistic(ctx, []byte(hexutil.Encode(bytesutil.PadTo([]byte("root"), 32))), cs, mf, cs, nil)
require.NoError(t, err)
assert.Equal(t, false, o)
})
t.Run("root is optimistic", func(t *testing.T) {
b, err := blocks.NewSignedBeaconBlock(util.NewBeaconBlock())
require.NoError(t, err)
b.SetStateRoot(bytesutil.PadTo([]byte("root"), 32))
db := dbtest.SetupDB(t)
require.NoError(t, db.SaveBlock(ctx, b))
fetcherSt, err := util.NewBeaconState()
require.NoError(t, err)
chainSt, err := util.NewBeaconState()
require.NoError(t, err)
require.NoError(t, chainSt.SetSlot(fieldparams.SlotsPerEpoch))
bRoot, err := b.Block().HashTreeRoot()
require.NoError(t, err)
cs := &chainmock.ChainService{State: chainSt, OptimisticRoots: map[[32]byte]bool{bRoot: true}}
mf := &testutil.MockStater{BeaconState: fetcherSt}
o, err := IsOptimistic(ctx, []byte(hexutil.Encode(bytesutil.PadTo([]byte("root"), 32))), cs, mf, cs, db)
require.NoError(t, err)
assert.Equal(t, true, o)
})
t.Run("root is not optimistic", func(t *testing.T) {
b, err := blocks.NewSignedBeaconBlock(util.NewBeaconBlock())
require.NoError(t, err)
b.SetStateRoot(bytesutil.PadTo([]byte("root"), 32))
db := dbtest.SetupDB(t)
require.NoError(t, db.SaveBlock(ctx, b))
fetcherSt, err := util.NewBeaconState()
require.NoError(t, err)
chainSt, err := util.NewBeaconState()
require.NoError(t, err)
require.NoError(t, chainSt.SetSlot(fieldparams.SlotsPerEpoch))
cs := &chainmock.ChainService{State: chainSt}
mf := &testutil.MockStater{BeaconState: fetcherSt}
o, err := IsOptimistic(ctx, []byte(hexutil.Encode(bytesutil.PadTo([]byte("root"), 32))), cs, mf, cs, db)
require.NoError(t, err)
assert.Equal(t, false, o)
})
t.Run("no canonical blocks", func(t *testing.T) {
b, err := blocks.NewSignedBeaconBlock(util.NewBeaconBlock())
require.NoError(t, err)
db := dbtest.SetupDB(t)
require.NoError(t, db.SaveBlock(ctx, b))
fetcherSt, err := util.NewBeaconState()
require.NoError(t, err)
chainSt, err := util.NewBeaconState()
require.NoError(t, err)
require.NoError(t, chainSt.SetSlot(fieldparams.SlotsPerEpoch))
cs := &chainmock.ChainService{Optimistic: false, State: chainSt, CanonicalRoots: map[[32]byte]bool{}}
mf := &testutil.MockStater{BeaconState: fetcherSt}
o, err := IsOptimistic(ctx, []byte(hexutil.Encode(bytesutil.PadTo([]byte("root"), 32))), nil, mf, cs, db)
require.NoError(t, err)
assert.Equal(t, true, o)
})
})
t.Run("slot", func(t *testing.T) {
t.Run("head is not optimistic", func(t *testing.T) {
cs := &chainmock.ChainService{Optimistic: false}

View File

@@ -15,18 +15,16 @@ go_library(
"//beacon-chain/core/blocks:go_default_library",
"//beacon-chain/core/epoch/precompute:go_default_library",
"//beacon-chain/core/validators:go_default_library",
"//beacon-chain/rpc/eth/shared:go_default_library",
"//beacon-chain/rpc/lookup:go_default_library",
"//beacon-chain/state:go_default_library",
"//beacon-chain/state/stategen:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//consensus-types/blocks:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//consensus-types/primitives:go_default_library",
"//network/http:go_default_library",
"//runtime/version:go_default_library",
"//time/slots:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_wealdtech_go_bytesutil//:go_default_library",
],
)

View File

@@ -7,17 +7,14 @@ import (
"strconv"
"strings"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/altair"
coreblocks "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/epoch/precompute"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/validators"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/shared"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
"github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
http2 "github.com/prysmaticlabs/prysm/v4/network/http"
"github.com/prysmaticlabs/prysm/v4/runtime/version"
@@ -31,16 +28,11 @@ func (s *Server) BlockRewards(w http.ResponseWriter, r *http.Request) {
blockId := segments[len(segments)-1]
blk, err := s.Blocker.Block(r.Context(), []byte(blockId))
if errJson := handleGetBlockError(blk, err); errJson != nil {
http2.WriteError(w, errJson)
if !shared.WriteBlockFetchError(w, blk, err) {
return
}
if blk.Version() == version.Phase0 {
errJson := &http2.DefaultErrorJson{
Message: "Block rewards are not supported for Phase 0 blocks",
Code: http.StatusBadRequest,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Block rewards are not supported for Phase 0 blocks", http.StatusBadRequest)
return
}
@@ -49,114 +41,66 @@ func (s *Server) BlockRewards(w http.ResponseWriter, r *http.Request) {
// To do this, we replay the state up to the block's slot, but before processing the block.
st, err := s.ReplayerBuilder.ReplayerForSlot(blk.Block().Slot()-1).ReplayToSlot(r.Context(), blk.Block().Slot())
if err != nil {
errJson := &http2.DefaultErrorJson{
Message: "Could not get state: " + err.Error(),
Code: http.StatusInternalServerError,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Could not get state: "+err.Error(), http.StatusInternalServerError)
return
}
proposerIndex := blk.Block().ProposerIndex()
initBalance, err := st.BalanceAtIndex(proposerIndex)
if err != nil {
errJson := &http2.DefaultErrorJson{
Message: "Could not get proposer's balance: " + err.Error(),
Code: http.StatusInternalServerError,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Could not get proposer's balance: "+err.Error(), http.StatusInternalServerError)
return
}
st, err = altair.ProcessAttestationsNoVerifySignature(r.Context(), st, blk)
if err != nil {
errJson := &http2.DefaultErrorJson{
Message: "Could not get attestation rewards" + err.Error(),
Code: http.StatusInternalServerError,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Could not get attestation rewards"+err.Error(), http.StatusInternalServerError)
return
}
attBalance, err := st.BalanceAtIndex(proposerIndex)
if err != nil {
errJson := &http2.DefaultErrorJson{
Message: "Could not get proposer's balance: " + err.Error(),
Code: http.StatusInternalServerError,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Could not get proposer's balance: "+err.Error(), http.StatusInternalServerError)
return
}
st, err = coreblocks.ProcessAttesterSlashings(r.Context(), st, blk.Block().Body().AttesterSlashings(), validators.SlashValidator)
if err != nil {
errJson := &http2.DefaultErrorJson{
Message: "Could not get attester slashing rewards: " + err.Error(),
Code: http.StatusInternalServerError,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Could not get attester slashing rewards: "+err.Error(), http.StatusInternalServerError)
return
}
attSlashingsBalance, err := st.BalanceAtIndex(proposerIndex)
if err != nil {
errJson := &http2.DefaultErrorJson{
Message: "Could not get proposer's balance: " + err.Error(),
Code: http.StatusInternalServerError,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Could not get proposer's balance: "+err.Error(), http.StatusInternalServerError)
return
}
st, err = coreblocks.ProcessProposerSlashings(r.Context(), st, blk.Block().Body().ProposerSlashings(), validators.SlashValidator)
if err != nil {
errJson := &http2.DefaultErrorJson{
Message: "Could not get proposer slashing rewards" + err.Error(),
Code: http.StatusInternalServerError,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Could not get proposer slashing rewards"+err.Error(), http.StatusInternalServerError)
return
}
proposerSlashingsBalance, err := st.BalanceAtIndex(proposerIndex)
if err != nil {
errJson := &http2.DefaultErrorJson{
Message: "Could not get proposer's balance: " + err.Error(),
Code: http.StatusInternalServerError,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Could not get proposer's balance: "+err.Error(), http.StatusInternalServerError)
return
}
sa, err := blk.Block().Body().SyncAggregate()
if err != nil {
errJson := &http2.DefaultErrorJson{
Message: "Could not get sync aggregate: " + err.Error(),
Code: http.StatusInternalServerError,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Could not get sync aggregate: "+err.Error(), http.StatusInternalServerError)
return
}
var syncCommitteeReward uint64
_, syncCommitteeReward, err = altair.ProcessSyncAggregate(r.Context(), st, sa)
if err != nil {
errJson := &http2.DefaultErrorJson{
Message: "Could not get sync aggregate rewards: " + err.Error(),
Code: http.StatusInternalServerError,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Could not get sync aggregate rewards: "+err.Error(), http.StatusInternalServerError)
return
}
optimistic, err := s.OptimisticModeFetcher.IsOptimistic(r.Context())
if err != nil {
errJson := &http2.DefaultErrorJson{
Message: "Could not get optimistic mode info: " + err.Error(),
Code: http.StatusInternalServerError,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Could not get optimistic mode info: "+err.Error(), http.StatusInternalServerError)
return
}
blkRoot, err := blk.Block().HashTreeRoot()
if err != nil {
errJson := &http2.DefaultErrorJson{
Message: "Could not get block root: " + err.Error(),
Code: http.StatusInternalServerError,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Could not get block root: "+err.Error(), http.StatusInternalServerError)
return
}
@@ -198,20 +142,12 @@ func (s *Server) AttestationRewards(w http.ResponseWriter, r *http.Request) {
optimistic, err := s.OptimisticModeFetcher.IsOptimistic(r.Context())
if err != nil {
errJson := &http2.DefaultErrorJson{
Message: "Could not get optimistic mode info: " + err.Error(),
Code: http.StatusInternalServerError,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Could not get optimistic mode info: "+err.Error(), http.StatusInternalServerError)
return
}
blkRoot, err := st.LatestBlockHeader().HashTreeRoot()
if err != nil {
errJson := &http2.DefaultErrorJson{
Message: "Could not get block root: " + err.Error(),
Code: http.StatusInternalServerError,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Could not get block root: "+err.Error(), http.StatusInternalServerError)
return
}
@@ -233,34 +169,21 @@ func (s *Server) SyncCommitteeRewards(w http.ResponseWriter, r *http.Request) {
blockId := segments[len(segments)-1]
blk, err := s.Blocker.Block(r.Context(), []byte(blockId))
if errJson := handleGetBlockError(blk, err); errJson != nil {
http2.WriteError(w, errJson)
if !shared.WriteBlockFetchError(w, blk, err) {
return
}
if blk.Version() == version.Phase0 {
errJson := &http2.DefaultErrorJson{
Message: "Sync committee rewards are not supported for Phase 0",
Code: http.StatusBadRequest,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Sync committee rewards are not supported for Phase 0", http.StatusBadRequest)
return
}
st, err := s.ReplayerBuilder.ReplayerForSlot(blk.Block().Slot()-1).ReplayToSlot(r.Context(), blk.Block().Slot())
if err != nil {
errJson := &http2.DefaultErrorJson{
Message: "Could not get state: " + err.Error(),
Code: http.StatusInternalServerError,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Could not get state: "+err.Error(), http.StatusInternalServerError)
return
}
sa, err := blk.Block().Body().SyncAggregate()
if err != nil {
errJson := &http2.DefaultErrorJson{
Message: "Could not get sync aggregate: " + err.Error(),
Code: http.StatusInternalServerError,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Could not get sync aggregate: "+err.Error(), http.StatusInternalServerError)
return
}
@@ -272,22 +195,14 @@ func (s *Server) SyncCommitteeRewards(w http.ResponseWriter, r *http.Request) {
for i, valIdx := range valIndices {
preProcessBals[i], err = st.BalanceAtIndex(valIdx)
if err != nil {
errJson := &http2.DefaultErrorJson{
Message: "Could not get validator's balance: " + err.Error(),
Code: http.StatusInternalServerError,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Could not get validator's balance: "+err.Error(), http.StatusInternalServerError)
return
}
}
_, proposerReward, err := altair.ProcessSyncAggregate(r.Context(), st, sa)
if err != nil {
errJson := &http2.DefaultErrorJson{
Message: "Could not get sync aggregate rewards: " + err.Error(),
Code: http.StatusInternalServerError,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Could not get sync aggregate rewards: "+err.Error(), http.StatusInternalServerError)
return
}
@@ -296,11 +211,7 @@ func (s *Server) SyncCommitteeRewards(w http.ResponseWriter, r *http.Request) {
for i, valIdx := range valIndices {
bal, err := st.BalanceAtIndex(valIdx)
if err != nil {
errJson := &http2.DefaultErrorJson{
Message: "Could not get validator's balance: " + err.Error(),
Code: http.StatusInternalServerError,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Could not get validator's balance: "+err.Error(), http.StatusInternalServerError)
return
}
rewards[i] = int(bal - preProcessBals[i]) // lint:ignore uintcast
@@ -311,20 +222,12 @@ func (s *Server) SyncCommitteeRewards(w http.ResponseWriter, r *http.Request) {
optimistic, err := s.OptimisticModeFetcher.IsOptimistic(r.Context())
if err != nil {
errJson := &http2.DefaultErrorJson{
Message: "Could not get optimistic mode info: " + err.Error(),
Code: http.StatusInternalServerError,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Could not get optimistic mode info: "+err.Error(), http.StatusInternalServerError)
return
}
blkRoot, err := blk.Block().HashTreeRoot()
if err != nil {
errJson := &http2.DefaultErrorJson{
Message: "Could not get block root: " + err.Error(),
Code: http.StatusInternalServerError,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Could not get block root: "+err.Error(), http.StatusInternalServerError)
return
}
@@ -347,46 +250,28 @@ func (s *Server) attRewardsState(w http.ResponseWriter, r *http.Request) (state.
segments := strings.Split(r.URL.Path, "/")
requestedEpoch, err := strconv.ParseUint(segments[len(segments)-1], 10, 64)
if err != nil {
errJson := &http2.DefaultErrorJson{
Message: "Could not decode epoch: " + err.Error(),
Code: http.StatusBadRequest,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Could not decode epoch: "+err.Error(), http.StatusBadRequest)
return nil, false
}
if primitives.Epoch(requestedEpoch) < params.BeaconConfig().AltairForkEpoch {
errJson := &http2.DefaultErrorJson{
Message: "Attestation rewards are not supported for Phase 0",
Code: http.StatusNotFound,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Attestation rewards are not supported for Phase 0", http.StatusNotFound)
return nil, false
}
currentEpoch := uint64(slots.ToEpoch(s.TimeFetcher.CurrentSlot()))
if requestedEpoch+1 >= currentEpoch {
errJson := &http2.DefaultErrorJson{
Code: http.StatusNotFound,
Message: "Attestation rewards are available after two epoch transitions to ensure all attestations have a chance of inclusion",
}
http2.WriteError(w, errJson)
http2.HandleError(w,
"Attestation rewards are available after two epoch transitions to ensure all attestations have a chance of inclusion",
http.StatusNotFound)
return nil, false
}
nextEpochEnd, err := slots.EpochEnd(primitives.Epoch(requestedEpoch + 1))
if err != nil {
errJson := &http2.DefaultErrorJson{
Message: "Could not get next epoch's ending slot: " + err.Error(),
Code: http.StatusInternalServerError,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Could not get next epoch's ending slot: "+err.Error(), http.StatusInternalServerError)
return nil, false
}
st, err := s.Stater.StateBySlot(r.Context(), nextEpochEnd)
if err != nil {
errJson := &http2.DefaultErrorJson{
Message: "Could not get state for epoch's starting slot: " + err.Error(),
Code: http.StatusInternalServerError,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Could not get state for epoch's starting slot: "+err.Error(), http.StatusInternalServerError)
return nil, false
}
return st, true
@@ -399,20 +284,12 @@ func attRewardsBalancesAndVals(
) (*precompute.Balance, []*precompute.Validator, []primitives.ValidatorIndex, bool) {
allVals, bal, err := altair.InitializePrecomputeValidators(r.Context(), st)
if err != nil {
errJson := &http2.DefaultErrorJson{
Message: "Could not initialize precompute validators: " + err.Error(),
Code: http.StatusBadRequest,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Could not initialize precompute validators: "+err.Error(), http.StatusBadRequest)
return nil, nil, nil, false
}
allVals, bal, err = altair.ProcessEpochParticipation(r.Context(), st, bal, allVals)
if err != nil {
errJson := &http2.DefaultErrorJson{
Message: "Could not process epoch participation: " + err.Error(),
Code: http.StatusBadRequest,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Could not process epoch participation: "+err.Error(), http.StatusBadRequest)
return nil, nil, nil, false
}
valIndices, ok := requestedValIndices(w, r, st, allVals)
@@ -463,11 +340,7 @@ func idealAttRewards(
}
deltas, err := altair.AttestationsDelta(st, bal, idealVals)
if err != nil {
errJson := &http2.DefaultErrorJson{
Message: "Could not get attestations delta: " + err.Error(),
Code: http.StatusInternalServerError,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Could not get attestations delta: "+err.Error(), http.StatusInternalServerError)
return nil, false
}
for i, d := range deltas {
@@ -499,11 +372,7 @@ func totalAttRewards(
}
deltas, err := altair.AttestationsDelta(st, bal, vals)
if err != nil {
errJson := &http2.DefaultErrorJson{
Message: "Could not get attestations delta: " + err.Error(),
Code: http.StatusInternalServerError,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Could not get attestations delta: "+err.Error(), http.StatusInternalServerError)
return nil, false
}
for i, d := range deltas {
@@ -529,11 +398,7 @@ func syncRewardsVals(
) ([]*precompute.Validator, []primitives.ValidatorIndex, bool) {
allVals, _, err := altair.InitializePrecomputeValidators(r.Context(), st)
if err != nil {
errJson := &http2.DefaultErrorJson{
Message: "Could not initialize precompute validators: " + err.Error(),
Code: http.StatusBadRequest,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Could not initialize precompute validators: "+err.Error(), http.StatusBadRequest)
return nil, nil, false
}
valIndices, ok := requestedValIndices(w, r, st, allVals)
@@ -543,22 +408,14 @@ func syncRewardsVals(
sc, err := st.CurrentSyncCommittee()
if err != nil {
errJson := &http2.DefaultErrorJson{
Message: "Could not get current sync committee: " + err.Error(),
Code: http.StatusBadRequest,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Could not get current sync committee: "+err.Error(), http.StatusBadRequest)
return nil, nil, false
}
allScIndices := make([]primitives.ValidatorIndex, len(sc.Pubkeys))
for i, pk := range sc.Pubkeys {
valIdx, ok := st.ValidatorIndexByPubkey(bytesutil.ToBytes48(pk))
if !ok {
errJson := &http2.DefaultErrorJson{
Message: fmt.Sprintf("No validator index found for pubkey %#x", pk),
Code: http.StatusBadRequest,
}
http2.WriteError(w, errJson)
http2.HandleError(w, fmt.Sprintf("No validator index found for pubkey %#x", pk), http.StatusBadRequest)
return nil, nil, false
}
allScIndices[i] = valIdx
@@ -583,11 +440,7 @@ func requestedValIndices(w http.ResponseWriter, r *http.Request, st state.Beacon
var rawValIds []string
if r.Body != http.NoBody {
if err := json.NewDecoder(r.Body).Decode(&rawValIds); err != nil {
errJson := &http2.DefaultErrorJson{
Message: "Could not decode validators: " + err.Error(),
Code: http.StatusBadRequest,
}
http2.WriteError(w, errJson)
http2.HandleError(w, "Could not decode validators: "+err.Error(), http.StatusBadRequest)
return nil, false
}
}
@@ -597,30 +450,18 @@ func requestedValIndices(w http.ResponseWriter, r *http.Request, st state.Beacon
if err != nil {
pubkey, err := bytesutil.FromHexString(v)
if err != nil || len(pubkey) != fieldparams.BLSPubkeyLength {
errJson := &http2.DefaultErrorJson{
Message: fmt.Sprintf("%s is not a validator index or pubkey", v),
Code: http.StatusBadRequest,
}
http2.WriteError(w, errJson)
http2.HandleError(w, fmt.Sprintf("%s is not a validator index or pubkey", v), http.StatusBadRequest)
return nil, false
}
var ok bool
valIndices[i], ok = st.ValidatorIndexByPubkey(bytesutil.ToBytes48(pubkey))
if !ok {
errJson := &http2.DefaultErrorJson{
Message: fmt.Sprintf("No validator index found for pubkey %#x", pubkey),
Code: http.StatusBadRequest,
}
http2.WriteError(w, errJson)
http2.HandleError(w, fmt.Sprintf("No validator index found for pubkey %#x", pubkey), http.StatusBadRequest)
return nil, false
}
} else {
if index >= uint64(st.NumValidators()) {
errJson := &http2.DefaultErrorJson{
Message: fmt.Sprintf("Validator index %d is too large. Maximum allowed index is %d", index, st.NumValidators()-1),
Code: http.StatusBadRequest,
}
http2.WriteError(w, errJson)
http2.HandleError(w, fmt.Sprintf("Validator index %d is too large. Maximum allowed index is %d", index, st.NumValidators()-1), http.StatusBadRequest)
return nil, false
}
valIndices[i] = primitives.ValidatorIndex(index)
@@ -635,25 +476,3 @@ func requestedValIndices(w http.ResponseWriter, r *http.Request, st state.Beacon
return valIndices, true
}
func handleGetBlockError(blk interfaces.ReadOnlySignedBeaconBlock, err error) *http2.DefaultErrorJson {
if errors.Is(err, lookup.BlockIdParseError{}) {
return &http2.DefaultErrorJson{
Message: "Invalid block ID: " + err.Error(),
Code: http.StatusBadRequest,
}
}
if err != nil {
return &http2.DefaultErrorJson{
Message: "Could not get block from block ID: " + err.Error(),
Code: http.StatusInternalServerError,
}
}
if err := blocks.BeaconBlockIsNil(blk); err != nil {
return &http2.DefaultErrorJson{
Message: "Could not find requested block: " + err.Error(),
Code: http.StatusNotFound,
}
}
return nil
}

View File

@@ -13,22 +13,22 @@ import (
)
type Attestation struct {
AggregationBits string `json:"aggregation_bits" validate:"required,hexadecimal"`
Data *AttestationData `json:"data" validate:"required"`
Signature string `json:"signature" validate:"required,hexadecimal"`
AggregationBits string `json:"aggregation_bits"`
Data *AttestationData `json:"data"`
Signature string `json:"signature"`
}
type AttestationData struct {
Slot string `json:"slot" validate:"required,number,gte=0"`
CommitteeIndex string `json:"index" validate:"required,number,gte=0"`
BeaconBlockRoot string `json:"beacon_block_root" validate:"required,hexadecimal"`
Source *Checkpoint `json:"source" validate:"required"`
Target *Checkpoint `json:"target" validate:"required"`
Slot string `json:"slot"`
CommitteeIndex string `json:"index"`
BeaconBlockRoot string `json:"beacon_block_root"`
Source *Checkpoint `json:"source"`
Target *Checkpoint `json:"target"`
}
type Checkpoint struct {
Epoch string `json:"epoch" validate:"required,number,gte=0"`
Root string `json:"root" validate:"required,hexadecimal"`
Epoch string `json:"epoch"`
Root string `json:"root"`
}
type Committee struct {
@@ -38,59 +38,59 @@ type Committee struct {
}
type SignedContributionAndProof struct {
Message *ContributionAndProof `json:"message" validate:"required"`
Signature string `json:"signature" validate:"required,hexadecimal"`
Message *ContributionAndProof `json:"message"`
Signature string `json:"signature"`
}
type ContributionAndProof struct {
AggregatorIndex string `json:"aggregator_index" validate:"required,number,gte=0"`
Contribution *SyncCommitteeContribution `json:"contribution" validate:"required"`
SelectionProof string `json:"selection_proof" validate:"required,hexadecimal"`
AggregatorIndex string `json:"aggregator_index"`
Contribution *SyncCommitteeContribution `json:"contribution"`
SelectionProof string `json:"selection_proof"`
}
type SyncCommitteeContribution struct {
Slot string `json:"slot" validate:"required,number,gte=0"`
BeaconBlockRoot string `json:"beacon_block_root" hex:"true" validate:"required,hexadecimal"`
SubcommitteeIndex string `json:"subcommittee_index" validate:"required,number,gte=0"`
AggregationBits string `json:"aggregation_bits" hex:"true" validate:"required,hexadecimal"`
Signature string `json:"signature" hex:"true" validate:"required,hexadecimal"`
Slot string `json:"slot"`
BeaconBlockRoot string `json:"beacon_block_root"`
SubcommitteeIndex string `json:"subcommittee_index"`
AggregationBits string `json:"aggregation_bits"`
Signature string `json:"signature"`
}
type SignedAggregateAttestationAndProof struct {
Message *AggregateAttestationAndProof `json:"message" validate:"required"`
Signature string `json:"signature" validate:"required,hexadecimal"`
Message *AggregateAttestationAndProof `json:"message"`
Signature string `json:"signature"`
}
type AggregateAttestationAndProof struct {
AggregatorIndex string `json:"aggregator_index" validate:"required,number,gte=0"`
Aggregate *Attestation `json:"aggregate" validate:"required"`
SelectionProof string `json:"selection_proof" validate:"required,hexadecimal"`
AggregatorIndex string `json:"aggregator_index"`
Aggregate *Attestation `json:"aggregate"`
SelectionProof string `json:"selection_proof"`
}
type SyncCommitteeSubscription struct {
ValidatorIndex string `json:"validator_index" validate:"required,number,gte=0"`
SyncCommitteeIndices []string `json:"sync_committee_indices" validate:"required,dive,number,gte=0"`
UntilEpoch string `json:"until_epoch" validate:"required,number,gte=0"`
ValidatorIndex string `json:"validator_index"`
SyncCommitteeIndices []string `json:"sync_committee_indices"`
UntilEpoch string `json:"until_epoch"`
}
type BeaconCommitteeSubscription struct {
ValidatorIndex string `json:"validator_index" validate:"required,number,gte=0"`
CommitteeIndex string `json:"committee_index" validate:"required,number,gte=0"`
CommitteesAtSlot string `json:"committees_at_slot" validate:"required,number,gte=0"`
Slot string `json:"slot" validate:"required,number,gte=0"`
ValidatorIndex string `json:"validator_index"`
CommitteeIndex string `json:"committee_index"`
CommitteesAtSlot string `json:"committees_at_slot"`
Slot string `json:"slot"`
IsAggregator bool `json:"is_aggregator"`
}
type ValidatorRegistration struct {
FeeRecipient string `json:"fee_recipient" validate:"required,hexadecimal"`
GasLimit string `json:"gas_limit" validate:"required,number,gte=0"`
Timestamp string `json:"timestamp" validate:"required,number,gte=0"`
Pubkey string `json:"pubkey" validate:"required,hexadecimal"`
FeeRecipient string `json:"fee_recipient"`
GasLimit string `json:"gas_limit"`
Timestamp string `json:"timestamp"`
Pubkey string `json:"pubkey"`
}
type SignedValidatorRegistration struct {
Message *ValidatorRegistration `json:"message" validate:"required"`
Signature string `json:"signature" validate:"required,hexadecimal"`
Message *ValidatorRegistration `json:"message"`
Signature string `json:"signature"`
}
type FeeRecipient struct {
@@ -99,13 +99,13 @@ type FeeRecipient struct {
}
type SignedVoluntaryExit struct {
Message *VoluntaryExit `json:"message" validate:"required"`
Signature string `json:"signature" validate:"required,hexadecimal"`
Message *VoluntaryExit `json:"message"`
Signature string `json:"signature"`
}
type VoluntaryExit struct {
Epoch string `json:"epoch" validate:"required,number,gte=0"`
ValidatorIndex string `json:"validator_index" validate:"required,number,gte=0"`
Epoch string `json:"epoch"`
ValidatorIndex string `json:"validator_index"`
}
type Fork struct {
@@ -135,10 +135,10 @@ func (s *Fork) ToConsensus() (*eth.Fork, error) {
}
type SyncCommitteeMessage struct {
Slot string `json:"slot" validate:"required,number,gte=0"`
BeaconBlockRoot string `json:"beacon_block_root" validate:"required,hexadecimal"`
ValidatorIndex string `json:"validator_index" validate:"required,number,gte=0"`
Signature string `json:"signature" validate:"required,hexadecimal"`
Slot string `json:"slot"`
BeaconBlockRoot string `json:"beacon_block_root"`
ValidatorIndex string `json:"validator_index"`
Signature string `json:"signature"`
}
func (s *SignedValidatorRegistration) ToConsensus() (*eth.SignedValidatorRegistrationV1, error) {

View File

@@ -29,10 +29,10 @@ go_library(
"//beacon-chain/rpc/eth/shared:go_default_library",
"//beacon-chain/rpc/lookup:go_default_library",
"//beacon-chain/state:go_default_library",
"//beacon-chain/state/state-native:go_default_library",
"//beacon-chain/sync:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//consensus-types:go_default_library",
"//consensus-types/primitives:go_default_library",
"//consensus-types/validator:go_default_library",
"//encoding/bytesutil:go_default_library",
@@ -45,7 +45,6 @@ go_library(
"//time/slots:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
"@com_github_go_playground_validator_v10//:go_default_library",
"@com_github_gorilla_mux//:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",

View File

@@ -13,7 +13,6 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/go-playground/validator/v10"
"github.com/gorilla/mux"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/builder"
@@ -25,9 +24,9 @@ import (
rpchelpers "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/helpers"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/shared"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
state_native "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native"
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
"github.com/prysmaticlabs/prysm/v4/config/params"
consensus_types "github.com/prysmaticlabs/prysm/v4/consensus-types"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
validator2 "github.com/prysmaticlabs/prysm/v4/consensus-types/validator"
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
@@ -50,6 +49,7 @@ func (s *Server) GetAggregateAttestation(w http.ResponseWriter, r *http.Request)
if !valid {
return
}
rawSlot := r.URL.Query().Get("slot")
slot, valid := shared.ValidateUint(w, "Slot", rawSlot)
if !valid {
@@ -122,11 +122,6 @@ func (s *Server) SubmitContributionAndProofs(w http.ResponseWriter, r *http.Requ
http2.HandleError(w, "No data submitted", http.StatusBadRequest)
return
}
validate := validator.New()
if err := validate.Struct(req); err != nil {
http2.HandleError(w, err.Error(), http.StatusBadRequest)
return
}
for _, item := range req.Data {
consensusItem, err := item.ToConsensus()
@@ -160,11 +155,6 @@ func (s *Server) SubmitAggregateAndProofs(w http.ResponseWriter, r *http.Request
http2.HandleError(w, "No data submitted", http.StatusBadRequest)
return
}
validate := validator.New()
if err := validate.Struct(req); err != nil {
http2.HandleError(w, err.Error(), http.StatusBadRequest)
return
}
broadcastFailed := false
for _, item := range req.Data {
@@ -220,11 +210,6 @@ func (s *Server) SubmitSyncCommitteeSubscription(w http.ResponseWriter, r *http.
http2.HandleError(w, "No data submitted", http.StatusBadRequest)
return
}
validate := validator.New()
if err := validate.Struct(req); err != nil {
http2.HandleError(w, err.Error(), http.StatusBadRequest)
return
}
st, err := s.HeadFetcher.HeadStateReadOnly(ctx)
if err != nil {
@@ -335,11 +320,6 @@ func (s *Server) SubmitBeaconCommitteeSubscription(w http.ResponseWriter, r *htt
http2.HandleError(w, "No data submitted", http.StatusBadRequest)
return
}
validate := validator.New()
if err := validate.Struct(req); err != nil {
http2.HandleError(w, err.Error(), http.StatusBadRequest)
return
}
st, err := s.HeadFetcher.HeadStateReadOnly(ctx)
if err != nil {
@@ -359,8 +339,8 @@ func (s *Server) SubmitBeaconCommitteeSubscription(w http.ResponseWriter, r *htt
subscriptions[i] = consensusItem
val, err := st.ValidatorAtIndexReadOnly(consensusItem.ValidatorIndex)
if err != nil {
if outOfRangeErr, ok := err.(*state_native.ValidatorIndexOutOfRangeError); ok {
http2.HandleError(w, "Could not get validator: "+outOfRangeErr.Error(), http.StatusBadRequest)
if errors.Is(err, consensus_types.ErrOutOfBounds) {
http2.HandleError(w, "Could not get validator: "+err.Error(), http.StatusBadRequest)
return
}
http2.HandleError(w, "Could not get validator: "+err.Error(), http.StatusInternalServerError)
@@ -557,13 +537,8 @@ func (s *Server) RegisterValidator(w http.ResponseWriter, r *http.Request) {
return
}
validate := validator.New()
registrations := make([]*ethpbalpha.SignedValidatorRegistrationV1, len(jsonRegistrations))
for i, registration := range jsonRegistrations {
if err := validate.Struct(registration); err != nil {
http2.HandleError(w, err.Error(), http.StatusBadRequest)
return
}
reg, err := registration.ToConsensus()
if err != nil {
http2.HandleError(w, err.Error(), http.StatusBadRequest)
@@ -855,6 +830,7 @@ func (s *Server) GetProposerDuties(w http.ResponseWriter, r *http.Request) {
pubkey48 := val.PublicKey()
pubkey := pubkey48[:]
for _, slot := range proposalSlots {
s.ProposerSlotIndexCache.SetProposerAndPayloadIDs(slot, index, [8]byte{} /* payloadID */, [32]byte{} /* head root */)
duties = append(duties, &ProposerDuty{
Pubkey: hexutil.Encode(pubkey),
ValidatorIndex: strconv.FormatUint(uint64(index), 10),
@@ -863,6 +839,8 @@ func (s *Server) GetProposerDuties(w http.ResponseWriter, r *http.Request) {
}
}
s.ProposerSlotIndexCache.PrunePayloadIDs(epochStartSlot)
dependentRoot, err := proposalDependentRoot(st, requestedEpoch)
if err != nil {
http2.HandleError(w, "Could not get dependent root: "+err.Error(), http.StatusInternalServerError)

View File

@@ -30,6 +30,7 @@ import (
func (s *Server) ProduceBlockV3(w http.ResponseWriter, r *http.Request) {
ctx, span := trace.StartSpan(r.Context(), "validator.ProduceBlockV3")
defer span.End()
if shared.IsSyncing(r.Context(), w, s.SyncChecker, s.HeadFetcher, s.TimeFetcher, s.OptimisticModeFetcher) {
return
}

View File

@@ -1856,6 +1856,9 @@ func TestGetProposerDuties(t *testing.T) {
expectedDuty = duty
}
}
vid, _, has := s.ProposerSlotIndexCache.GetProposerPayloadIDs(11, [32]byte{})
require.Equal(t, true, has)
require.Equal(t, primitives.ValidatorIndex(12289), vid)
require.NotNil(t, expectedDuty, "Expected duty for slot 11 not found")
assert.Equal(t, "12289", expectedDuty.ValidatorIndex)
assert.Equal(t, hexutil.Encode(pubKeys[12289]), expectedDuty.Pubkey)
@@ -1895,10 +1898,52 @@ func TestGetProposerDuties(t *testing.T) {
expectedDuty = duty
}
}
vid, _, has := s.ProposerSlotIndexCache.GetProposerPayloadIDs(43, [32]byte{})
require.Equal(t, true, has)
require.Equal(t, primitives.ValidatorIndex(1360), vid)
require.NotNil(t, expectedDuty, "Expected duty for slot 43 not found")
assert.Equal(t, "1360", expectedDuty.ValidatorIndex)
assert.Equal(t, hexutil.Encode(pubKeys[1360]), expectedDuty.Pubkey)
})
t.Run("prune payload ID cache", func(t *testing.T) {
bs, err := transition.GenesisBeaconState(context.Background(), deposits, 0, eth1Data)
require.NoError(t, err, "Could not set up genesis state")
require.NoError(t, bs.SetSlot(params.BeaconConfig().SlotsPerEpoch))
require.NoError(t, bs.SetBlockRoots(roots))
chainSlot := params.BeaconConfig().SlotsPerEpoch
chain := &mockChain.ChainService{
State: bs, Root: genesisRoot[:], Slot: &chainSlot,
}
s := &Server{
Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{params.BeaconConfig().SlotsPerEpoch: bs}},
HeadFetcher: chain,
TimeFetcher: chain,
OptimisticModeFetcher: chain,
SyncChecker: &mockSync.Sync{IsSyncing: false},
ProposerSlotIndexCache: cache.NewProposerPayloadIDsCache(),
}
s.ProposerSlotIndexCache.SetProposerAndPayloadIDs(1, 1, [8]byte{1}, [32]byte{2})
s.ProposerSlotIndexCache.SetProposerAndPayloadIDs(31, 2, [8]byte{2}, [32]byte{3})
s.ProposerSlotIndexCache.SetProposerAndPayloadIDs(32, 4309, [8]byte{3}, [32]byte{4})
request := httptest.NewRequest(http.MethodGet, "http://www.example.com/eth/v1/validator/duties/proposer/{epoch}", nil)
request = mux.SetURLVars(request, map[string]string{"epoch": "1"})
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.GetProposerDuties(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
vid, _, has := s.ProposerSlotIndexCache.GetProposerPayloadIDs(1, [32]byte{})
require.Equal(t, false, has)
require.Equal(t, primitives.ValidatorIndex(0), vid)
vid, _, has = s.ProposerSlotIndexCache.GetProposerPayloadIDs(2, [32]byte{})
require.Equal(t, false, has)
require.Equal(t, primitives.ValidatorIndex(0), vid)
vid, _, has = s.ProposerSlotIndexCache.GetProposerPayloadIDs(32, [32]byte{})
require.Equal(t, true, has)
require.Equal(t, primitives.ValidatorIndex(10565), vid)
})
t.Run("epoch out of bounds", func(t *testing.T) {
bs, err := transition.GenesisBeaconState(context.Background(), deposits, 0, eth1Data)
require.NoError(t, err, "Could not set up genesis state")

View File

@@ -11,19 +11,19 @@ type AggregateAttestationResponse struct {
}
type SubmitContributionAndProofsRequest struct {
Data []*shared.SignedContributionAndProof `json:"data" validate:"required,dive"`
Data []*shared.SignedContributionAndProof `json:"data"`
}
type SubmitAggregateAndProofsRequest struct {
Data []*shared.SignedAggregateAttestationAndProof `json:"data" validate:"required,dive"`
Data []*shared.SignedAggregateAttestationAndProof `json:"data"`
}
type SubmitSyncCommitteeSubscriptionsRequest struct {
Data []*shared.SyncCommitteeSubscription `json:"data" validate:"required,dive"`
Data []*shared.SyncCommitteeSubscription `json:"data"`
}
type SubmitBeaconCommitteeSubscriptionsRequest struct {
Data []*shared.BeaconCommitteeSubscription `json:"data" validate:"required,dive"`
Data []*shared.BeaconCommitteeSubscription `json:"data"`
}
type GetAttestationDataResponse struct {

View File

@@ -19,6 +19,7 @@ go_library(
"//consensus-types/primitives:go_default_library",
"//encoding/bytesutil: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",
"@io_opencensus_go//trace:go_default_library",
],

View File

@@ -3,7 +3,9 @@ package lookup
import (
"context"
"strconv"
"strings"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/db"
@@ -47,6 +49,7 @@ type BeaconDbBlocker struct {
// - "justified"
// - <slot>
// - <hex encoded block root with '0x' prefix>
// - <block root>
func (p *BeaconDbBlocker) Block(ctx context.Context, id []byte) (interfaces.ReadOnlySignedBeaconBlock, error) {
var err error
var blk interfaces.ReadOnlySignedBeaconBlock
@@ -69,7 +72,18 @@ func (p *BeaconDbBlocker) Block(ctx context.Context, id []byte) (interfaces.Read
return nil, errors.Wrap(err, "could not retrieve genesis block")
}
default:
if len(id) == 32 {
stringId := strings.ToLower(string(id))
if len(stringId) >= 2 && stringId[:2] == "0x" {
decoded, err := hexutil.Decode(string(id))
if err != nil {
e := NewBlockIdParseError(err)
return nil, &e
}
blk, err = p.BeaconDB.Block(ctx, bytesutil.ToBytes32(decoded))
if err != nil {
return nil, errors.Wrap(err, "could not retrieve block")
}
} else if len(id) == 32 {
blk, err = p.BeaconDB.Block(ctx, bytesutil.ToBytes32(id))
if err != nil {
return nil, errors.Wrap(err, "could not retrieve block")

View File

@@ -6,6 +6,7 @@ import (
"reflect"
"testing"
"github.com/ethereum/go-ethereum/common/hexutil"
mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing"
dbtesting "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/testutil"
@@ -116,6 +117,11 @@ func TestGetBlock(t *testing.T) {
blockID: bytesutil.PadTo([]byte("hi there"), 32),
want: nil,
},
{
name: "hex",
blockID: []byte(hexutil.Encode(blkContainers[20].BlockRoot)),
want: blkContainers[20].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block,
},
{
name: "no block",
blockID: []byte("105"),

View File

@@ -7,6 +7,7 @@ import (
"strconv"
"strings"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/db"
@@ -94,6 +95,7 @@ type BeaconDbStater struct {
// - "justified"
// - <slot>
// - <hex encoded state root with '0x' prefix>
// - <state root>
func (p *BeaconDbStater) State(ctx context.Context, stateId []byte) (state.BeaconState, error) {
var (
s state.BeaconState
@@ -141,7 +143,15 @@ func (p *BeaconDbStater) State(ctx context.Context, stateId []byte) (state.Beaco
return nil, errors.Wrap(err, "could not get justified state")
}
default:
if len(stateId) == 32 {
stringId := strings.ToLower(string(stateId))
if len(stringId) >= 2 && stringId[:2] == "0x" {
decoded, parseErr := hexutil.Decode(string(stateId))
if parseErr != nil {
e := NewStateIdParseError(parseErr)
return nil, &e
}
s, err = p.stateByRoot(ctx, decoded)
} else if len(stateId) == 32 {
s, err = p.stateByRoot(ctx, stateId)
} else {
slotNumber, parseErr := strconv.ParseUint(stateIdString, 10, 64)

View File

@@ -140,7 +140,26 @@ func TestGetState(t *testing.T) {
assert.DeepEqual(t, stateRoot, sRoot)
})
t.Run("hex_root", func(t *testing.T) {
t.Run("hex", func(t *testing.T) {
hex := "0x" + strings.Repeat("0", 63) + "1"
root, err := hexutil.Decode(hex)
require.NoError(t, err)
stateGen := mockstategen.NewMockService()
stateGen.StatesByRoot[bytesutil.ToBytes32(root)] = newBeaconState
p := BeaconDbStater{
ChainInfoFetcher: &chainMock.ChainService{State: newBeaconState},
StateGenService: stateGen,
}
s, err := p.State(ctx, []byte(hex))
require.NoError(t, err)
sRoot, err := s.HashTreeRoot(ctx)
require.NoError(t, err)
assert.DeepEqual(t, stateRoot, sRoot)
})
t.Run("root", func(t *testing.T) {
stateId, err := hexutil.Decode("0x" + strings.Repeat("0", 63) + "1")
require.NoError(t, err)
stateGen := mockstategen.NewMockService()
@@ -158,7 +177,7 @@ func TestGetState(t *testing.T) {
assert.DeepEqual(t, stateRoot, sRoot)
})
t.Run("hex_root_not_found", func(t *testing.T) {
t.Run("root not found", func(t *testing.T) {
p := BeaconDbStater{
ChainInfoFetcher: &chainMock.ChainService{State: newBeaconState},
}

View File

@@ -601,10 +601,6 @@ func (bs *Server) GetValidatorQueue(
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get active validator count: %v", err)
}
churnLimit, err := helpers.ValidatorChurnLimit(activeValidatorCount)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not compute churn limit: %v", err)
}
exitQueueEpoch := primitives.Epoch(0)
for _, i := range exitEpochs {
@@ -619,7 +615,8 @@ func (bs *Server) GetValidatorQueue(
}
}
// Prevent churn limit from causing index out of bound issues.
if churnLimit < exitQueueChurn {
exitChurnLimit := helpers.ValidatorExitChurnLimit(activeValidatorCount)
if exitChurnLimit < exitQueueChurn {
// If we are above the churn limit, we simply increase the churn by one.
exitQueueEpoch++
}
@@ -645,6 +642,10 @@ func (bs *Server) GetValidatorQueue(
exitQueueKeys[i] = vals[idx].PublicKey
}
churnLimit := helpers.ValidatorActivationChurnLimit(activeValidatorCount)
if headState.Version() >= version.Deneb {
churnLimit = helpers.ValidatorActivationChurnLimitDeneb(activeValidatorCount)
}
return &ethpb.ValidatorQueue{
ChurnLimit: churnLimit,
ActivationPublicKeys: activationQueueKeys,

View File

@@ -28,6 +28,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v4/runtime/version"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
@@ -422,10 +423,11 @@ func (is *infostream) calculateActivationTimeForPendingValidators(res []*ethpb.V
// Loop over epochs, roughly simulating progression.
for curEpoch := epoch + 1; len(sortedIndices) > 0 && len(pendingValidators) > 0; curEpoch++ {
toProcess, err := helpers.ValidatorChurnLimit(numAttestingValidators)
if err != nil {
log.WithError(err).Error("Could not determine validator churn limit")
toProcess := helpers.ValidatorActivationChurnLimit(numAttestingValidators)
if headState.Version() >= version.Deneb {
toProcess = helpers.ValidatorActivationChurnLimitDeneb(numAttestingValidators)
}
if toProcess > uint64(len(sortedIndices)) {
toProcess = uint64(len(sortedIndices))
}

View File

@@ -1370,8 +1370,7 @@ func TestServer_GetValidatorQueue_PendingActivation(t *testing.T) {
}
activeValidatorCount, err := helpers.ActiveValidatorCount(context.Background(), headState, coreTime.CurrentEpoch(headState))
require.NoError(t, err)
wantChurn, err := helpers.ValidatorChurnLimit(activeValidatorCount)
require.NoError(t, err)
wantChurn := helpers.ValidatorActivationChurnLimit(activeValidatorCount)
assert.Equal(t, wantChurn, res.ChurnLimit)
assert.DeepEqual(t, wanted, res.ActivationPublicKeys)
wantedActiveIndices := []primitives.ValidatorIndex{2, 1, 0}
@@ -1412,8 +1411,7 @@ func TestServer_GetValidatorQueue_ExitedValidatorLeavesQueue(t *testing.T) {
}
activeValidatorCount, err := helpers.ActiveValidatorCount(context.Background(), headState, coreTime.CurrentEpoch(headState))
require.NoError(t, err)
wantChurn, err := helpers.ValidatorChurnLimit(activeValidatorCount)
require.NoError(t, err)
wantChurn := helpers.ValidatorExitChurnLimit(activeValidatorCount)
assert.Equal(t, wantChurn, res.ChurnLimit)
assert.DeepEqual(t, wanted, res.ExitPublicKeys)
wantedExitIndices := []primitives.ValidatorIndex{1}
@@ -1472,8 +1470,7 @@ func TestServer_GetValidatorQueue_PendingExit(t *testing.T) {
}
activeValidatorCount, err := helpers.ActiveValidatorCount(context.Background(), headState, coreTime.CurrentEpoch(headState))
require.NoError(t, err)
wantChurn, err := helpers.ValidatorChurnLimit(activeValidatorCount)
require.NoError(t, err)
wantChurn := helpers.ValidatorExitChurnLimit(activeValidatorCount)
assert.Equal(t, wantChurn, res.ChurnLimit)
assert.DeepEqual(t, wanted, res.ExitPublicKeys)
}

View File

@@ -1,34 +0,0 @@
load("@prysm//tools/go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = [
"attestations.go",
"blocks.go",
"server.go",
],
importpath = "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/prysm/v1alpha1/slasher",
visibility = ["//beacon-chain:__subpackages__"],
deps = [
"//beacon-chain/slasher:go_default_library",
"//consensus-types/primitives:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"@org_golang_google_grpc//codes:go_default_library",
"@org_golang_google_grpc//status:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = [
"attestations_test.go",
"server_test.go",
],
embed = [":go_default_library"],
deps = [
"//beacon-chain/slasher/mock:go_default_library",
"//consensus-types/primitives:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//testing/require:go_default_library",
],
)

View File

@@ -1,43 +0,0 @@
package slasher
import (
"context"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
// IsSlashableAttestation returns an attester slashing if an input
// attestation is found to be slashable.
func (s *Server) IsSlashableAttestation(
ctx context.Context, req *ethpb.IndexedAttestation,
) (*ethpb.AttesterSlashingResponse, error) {
attesterSlashings, err := s.SlashingChecker.IsSlashableAttestation(ctx, req)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not determine if attestation is slashable: %v", err)
}
if len(attesterSlashings) > 0 {
return &ethpb.AttesterSlashingResponse{
AttesterSlashings: attesterSlashings,
}, nil
}
return &ethpb.AttesterSlashingResponse{}, nil
}
// HighestAttestations returns the highest source and target epochs attested for
// validator indices that have been observed by slasher.
func (s *Server) HighestAttestations(
ctx context.Context, req *ethpb.HighestAttestationRequest,
) (*ethpb.HighestAttestationResponse, error) {
valIndices := make([]primitives.ValidatorIndex, len(req.ValidatorIndices))
for i, valIdx := range req.ValidatorIndices {
valIndices[i] = primitives.ValidatorIndex(valIdx)
}
atts, err := s.SlashingChecker.HighestAttestations(ctx, valIndices)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get highest attestations: %v", err)
}
return &ethpb.HighestAttestationResponse{Attestations: atts}, nil
}

View File

@@ -1,63 +0,0 @@
package slasher
import (
"context"
"testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/slasher/mock"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v4/testing/require"
)
func TestServer_HighestAttestations(t *testing.T) {
highestAtts := map[primitives.ValidatorIndex]*ethpb.HighestAttestation{
0: {
ValidatorIndex: 0,
HighestSourceEpoch: 1,
HighestTargetEpoch: 2,
},
1: {
ValidatorIndex: 1,
HighestSourceEpoch: 2,
HighestTargetEpoch: 3,
},
}
mockSlasher := &mock.MockSlashingChecker{
HighestAtts: highestAtts,
}
s := Server{SlashingChecker: mockSlasher}
ctx := context.Background()
t.Run("single index found", func(t *testing.T) {
resp, err := s.HighestAttestations(ctx, &ethpb.HighestAttestationRequest{
ValidatorIndices: []uint64{0},
})
require.NoError(t, err)
require.Equal(t, 1, len(resp.Attestations))
require.DeepEqual(t, highestAtts[0], resp.Attestations[0])
})
t.Run("single index not found", func(t *testing.T) {
resp, err := s.HighestAttestations(ctx, &ethpb.HighestAttestationRequest{
ValidatorIndices: []uint64{3},
})
require.NoError(t, err)
require.Equal(t, 0, len(resp.Attestations))
})
t.Run("multiple indices all found", func(t *testing.T) {
resp, err := s.HighestAttestations(ctx, &ethpb.HighestAttestationRequest{
ValidatorIndices: []uint64{0, 1},
})
require.NoError(t, err)
require.Equal(t, 2, len(resp.Attestations))
require.DeepEqual(t, highestAtts[0], resp.Attestations[0])
require.DeepEqual(t, highestAtts[1], resp.Attestations[1])
})
t.Run("multiple indices some not found", func(t *testing.T) {
resp, err := s.HighestAttestations(ctx, &ethpb.HighestAttestationRequest{
ValidatorIndices: []uint64{0, 3},
})
require.NoError(t, err)
require.Equal(t, 1, len(resp.Attestations))
require.DeepEqual(t, highestAtts[0], resp.Attestations[0])
})
}

View File

@@ -1,28 +0,0 @@
package slasher
import (
"context"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
// IsSlashableBlock returns a proposer slashing if an input
// signed beacon block header is found to be slashable.
func (s *Server) IsSlashableBlock(
ctx context.Context, req *ethpb.SignedBeaconBlockHeader,
) (*ethpb.ProposerSlashingResponse, error) {
proposerSlashing, err := s.SlashingChecker.IsSlashableBlock(ctx, req)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not determine if block is slashable: %v", err)
}
if proposerSlashing == nil {
return &ethpb.ProposerSlashingResponse{
ProposerSlashings: []*ethpb.ProposerSlashing{},
}, nil
}
return &ethpb.ProposerSlashingResponse{
ProposerSlashings: []*ethpb.ProposerSlashing{proposerSlashing},
}, nil
}

View File

@@ -1,12 +0,0 @@
// Package slasher defines a gRPC server implementation of a slasher service
// which allows for checking if attestations or blocks are slashable.
package slasher
import (
slasherservice "github.com/prysmaticlabs/prysm/v4/beacon-chain/slasher"
)
// Server defines a server implementation of the gRPC slasher service.
type Server struct {
SlashingChecker slasherservice.SlashingChecker
}

View File

@@ -1,54 +0,0 @@
package slasher
import (
"context"
"testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/slasher/mock"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v4/testing/require"
)
func TestServer_IsSlashableAttestation_SlashingFound(t *testing.T) {
mockSlasher := &mock.MockSlashingChecker{
AttesterSlashingFound: true,
}
s := Server{SlashingChecker: mockSlasher}
ctx := context.Background()
slashing, err := s.IsSlashableAttestation(ctx, &ethpb.IndexedAttestation{})
require.NoError(t, err)
require.Equal(t, true, len(slashing.AttesterSlashings) > 0)
}
func TestServer_IsSlashableAttestation_SlashingNotFound(t *testing.T) {
mockSlasher := &mock.MockSlashingChecker{
AttesterSlashingFound: false,
}
s := Server{SlashingChecker: mockSlasher}
ctx := context.Background()
slashing, err := s.IsSlashableAttestation(ctx, &ethpb.IndexedAttestation{})
require.NoError(t, err)
require.Equal(t, true, len(slashing.AttesterSlashings) == 0)
}
func TestServer_IsSlashableBlock_SlashingFound(t *testing.T) {
mockSlasher := &mock.MockSlashingChecker{
ProposerSlashingFound: true,
}
s := Server{SlashingChecker: mockSlasher}
ctx := context.Background()
slashing, err := s.IsSlashableBlock(ctx, &ethpb.SignedBeaconBlockHeader{})
require.NoError(t, err)
require.Equal(t, true, len(slashing.ProposerSlashings) > 0)
}
func TestServer_IsSlashableBlock_SlashingNotFound(t *testing.T) {
mockSlasher := &mock.MockSlashingChecker{
ProposerSlashingFound: false,
}
s := Server{SlashingChecker: mockSlasher}
ctx := context.Background()
slashing, err := s.IsSlashableBlock(ctx, &ethpb.SignedBeaconBlockHeader{})
require.NoError(t, err)
require.Equal(t, true, len(slashing.ProposerSlashings) == 0)
}

View File

@@ -191,8 +191,6 @@ func (vs *Server) duties(ctx context.Context, req *ethpb.DutiesRequest) (*ethpb.
for _, slot := range nextProposerIndexToSlots[idx] {
vs.ProposerSlotIndexCache.SetProposerAndPayloadIDs(slot, idx, [8]byte{} /* payloadID */, [32]byte{} /* head root */)
}
// Prune payload ID cache for any slots before request slot.
vs.ProposerSlotIndexCache.PrunePayloadIDs(epochStartSlot)
} else {
// If the validator isn't in the beacon state, try finding their deposit to determine their status.
// We don't need the lastActiveValidatorFn because we don't use the response in this.
@@ -237,6 +235,8 @@ func (vs *Server) duties(ctx context.Context, req *ethpb.DutiesRequest) (*ethpb.
core.AssignValidatorToSubnetProto(pubKey, assignment.Status)
core.AssignValidatorToSubnetProto(pubKey, nextAssignment.Status)
}
// Prune payload ID cache for any slots before request slot.
vs.ProposerSlotIndexCache.PrunePayloadIDs(epochStartSlot)
return &ethpb.DutiesResponse{
Duties: validatorAssignments,

View File

@@ -20,7 +20,6 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/transition"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/db/kv"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
"github.com/prysmaticlabs/prysm/v4/config/features"
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
"github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
@@ -109,68 +108,9 @@ func (vs *Server) GetBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (
var blobBundle *enginev1.BlobsBundle
var blindBlobBundle *enginev1.BlindedBlobsBundle
if features.Get().BuildBlockParallel {
blindBlobBundle, blobBundle, err = vs.BuildBlockParallel(ctx, sBlk, head)
if err != nil {
return nil, errors.Wrap(err, "could not build block in parallel")
}
} else {
// Set eth1 data.
eth1Data, err := vs.eth1DataMajorityVote(ctx, head)
if err != nil {
eth1Data = &ethpb.Eth1Data{DepositRoot: params.BeaconConfig().ZeroHash[:], BlockHash: params.BeaconConfig().ZeroHash[:]}
log.WithError(err).Error("Could not get eth1data")
}
sBlk.SetEth1Data(eth1Data)
// Set deposit and attestation.
deposits, atts, err := vs.packDepositsAndAttestations(ctx, head, eth1Data) // TODO: split attestations and deposits
if err != nil {
sBlk.SetDeposits([]*ethpb.Deposit{})
sBlk.SetAttestations([]*ethpb.Attestation{})
log.WithError(err).Error("Could not pack deposits and attestations")
} else {
sBlk.SetDeposits(deposits)
sBlk.SetAttestations(atts)
}
// Set slashings.
validProposerSlashings, validAttSlashings := vs.getSlashings(ctx, head)
sBlk.SetProposerSlashings(validProposerSlashings)
sBlk.SetAttesterSlashings(validAttSlashings)
// Set exits.
sBlk.SetVoluntaryExits(vs.getExits(head, req.Slot))
// Set sync aggregate. New in Altair.
vs.setSyncAggregate(ctx, sBlk)
// Get local and builder (if enabled) payloads. Set execution data. New in Bellatrix.
var overrideBuilder bool
var localPayload interfaces.ExecutionData
localPayload, blobBundle, overrideBuilder, err = vs.getLocalPayloadAndBlobs(ctx, sBlk.Block(), head)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get local payload: %v", err)
}
// There's no reason to try to get a builder bid if local override is true.
var builderPayload interfaces.ExecutionData
if !overrideBuilder {
builderPayload, blindBlobBundle, err = vs.getBuilderPayloadAndBlobs(ctx, sBlk.Block().Slot(), sBlk.Block().ProposerIndex())
if err != nil {
builderGetPayloadMissCount.Inc()
log.WithError(err).Error("Could not get builder payload")
}
}
if err := setExecutionData(ctx, sBlk, localPayload, builderPayload); err != nil {
return nil, status.Errorf(codes.Internal, "Could not set execution data: %v", err)
}
// Set bls to execution change. New in Capella.
vs.setBlsToExecData(sBlk, head)
if err := setKzgCommitments(sBlk, blobBundle, blindBlobBundle); err != nil {
return nil, status.Errorf(codes.Internal, "Could not set kzg commitment: %v", err)
}
blindBlobBundle, blobBundle, err = vs.BuildBlockParallel(ctx, sBlk, head, req.SkipMevBoost)
if err != nil {
return nil, errors.Wrap(err, "could not build block in parallel")
}
sr, err := vs.computeStateRoot(ctx, sBlk)
@@ -197,7 +137,7 @@ func (vs *Server) GetBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (
return vs.constructGenericBeaconBlock(sBlk, blindBlobs, fullBlobs)
}
func (vs *Server) BuildBlockParallel(ctx context.Context, sBlk interfaces.SignedBeaconBlock, head state.BeaconState) (*enginev1.BlindedBlobsBundle, *enginev1.BlobsBundle, error) {
func (vs *Server) BuildBlockParallel(ctx context.Context, sBlk interfaces.SignedBeaconBlock, head state.BeaconState, skipMevBoost bool) (*enginev1.BlindedBlobsBundle, *enginev1.BlobsBundle, error) {
// Build consensus fields in background
var wg sync.WaitGroup
wg.Add(1)
@@ -246,6 +186,7 @@ func (vs *Server) BuildBlockParallel(ctx context.Context, sBlk interfaces.Signed
// There's no reason to try to get a builder bid if local override is true.
var builderPayload interfaces.ExecutionData
var blindBlobsBundle *enginev1.BlindedBlobsBundle
overrideBuilder = overrideBuilder || skipMevBoost // Skip using mev-boost if requested by the caller.
if !overrideBuilder {
builderPayload, blindBlobsBundle, err = vs.getBuilderPayloadAndBlobs(ctx, sBlk.Block().Slot(), sBlk.Block().ProposerIndex())
if err != nil {

View File

@@ -35,7 +35,10 @@ func (vs *Server) GetSyncMessageBlockRoot(
// SubmitSyncMessage submits the sync committee message to the network.
// It also saves the sync committee message into the pending pool for block inclusion.
func (vs *Server) SubmitSyncMessage(ctx context.Context, msg *ethpb.SyncCommitteeMessage) (*emptypb.Empty, error) {
return &emptypb.Empty{}, vs.CoreService.SubmitSyncMessage(ctx, msg)
if err := vs.CoreService.SubmitSyncMessage(ctx, msg); err != nil {
return &emptypb.Empty{}, status.Errorf(core.ErrorReasonToGRPC(err.Reason), err.Err.Error())
}
return &emptypb.Empty{}, nil
}
// GetSyncSubcommitteeIndex is called by a sync committee participant to get

View File

@@ -74,7 +74,6 @@ go_test(
"//beacon-chain/db/testing:go_default_library",
"//beacon-chain/forkchoice/doubly-linked-tree:go_default_library",
"//beacon-chain/operations/slashings/mock:go_default_library",
"//beacon-chain/slasher/mock:go_default_library",
"//beacon-chain/slasher/types:go_default_library",
"//beacon-chain/startup:go_default_library",
"//beacon-chain/state/stategen:go_default_library",

View File

@@ -1,13 +0,0 @@
load("@prysm//tools/go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["mock_slashing_checker.go"],
importpath = "github.com/prysmaticlabs/prysm/v4/beacon-chain/slasher/mock",
visibility = ["//visibility:public"],
deps = [
"//config/params:go_default_library",
"//consensus-types/primitives:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
],
)

View File

@@ -1,73 +0,0 @@
package mock
import (
"context"
"github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
)
type MockSlashingChecker struct {
AttesterSlashingFound bool
ProposerSlashingFound bool
HighestAtts map[primitives.ValidatorIndex]*ethpb.HighestAttestation
}
func (s *MockSlashingChecker) HighestAttestations(
_ context.Context, indices []primitives.ValidatorIndex,
) ([]*ethpb.HighestAttestation, error) {
atts := make([]*ethpb.HighestAttestation, 0, len(indices))
for _, valIdx := range indices {
att, ok := s.HighestAtts[valIdx]
if !ok {
continue
}
atts = append(atts, att)
}
return atts, nil
}
func (s *MockSlashingChecker) IsSlashableBlock(_ context.Context, _ *ethpb.SignedBeaconBlockHeader) (*ethpb.ProposerSlashing, error) {
if s.ProposerSlashingFound {
return &ethpb.ProposerSlashing{
Header_1: &ethpb.SignedBeaconBlockHeader{
Header: &ethpb.BeaconBlockHeader{
Slot: 0,
ProposerIndex: 0,
ParentRoot: params.BeaconConfig().ZeroHash[:],
StateRoot: params.BeaconConfig().ZeroHash[:],
BodyRoot: params.BeaconConfig().ZeroHash[:],
},
Signature: params.BeaconConfig().EmptySignature[:],
},
Header_2: &ethpb.SignedBeaconBlockHeader{
Header: &ethpb.BeaconBlockHeader{
Slot: 0,
ProposerIndex: 0,
ParentRoot: params.BeaconConfig().ZeroHash[:],
StateRoot: params.BeaconConfig().ZeroHash[:],
BodyRoot: params.BeaconConfig().ZeroHash[:],
},
Signature: params.BeaconConfig().EmptySignature[:],
},
}, nil
}
return nil, nil
}
func (s *MockSlashingChecker) IsSlashableAttestation(_ context.Context, _ *ethpb.IndexedAttestation) ([]*ethpb.AttesterSlashing, error) {
if s.AttesterSlashingFound {
return []*ethpb.AttesterSlashing{
{
Attestation_1: &ethpb.IndexedAttestation{
Data: &ethpb.AttestationData{},
},
Attestation_2: &ethpb.IndexedAttestation{
Data: &ethpb.AttestationData{},
},
},
}, nil
}
return nil, nil
}

View File

@@ -9,7 +9,6 @@ import (
"github.com/prysmaticlabs/prysm/v4/async/event"
mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing"
dbtest "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing"
mockslasher "github.com/prysmaticlabs/prysm/v4/beacon-chain/slasher/mock"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
mockSync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync/initial-sync/testing"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
@@ -21,7 +20,6 @@ import (
)
var _ = SlashingChecker(&Service{})
var _ = SlashingChecker(&mockslasher.MockSlashingChecker{})
func TestMain(m *testing.M) {
logrus.SetLevel(logrus.DebugLevel)

View File

@@ -7,12 +7,11 @@ go_library(
"field_trie_helpers.go",
],
importpath = "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/fieldtrie",
visibility = ["//beacon-chain:__subpackages__"],
visibility = ["//visibility:public"],
deps = [
"//beacon-chain/state/state-native/custom-types:go_default_library",
"//beacon-chain/state/state-native/types:go_default_library",
"//beacon-chain/state/stateutil:go_default_library",
"//encoding/bytesutil:go_default_library",
"//math:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"@com_github_pkg_errors//:go_default_library",

View File

@@ -31,11 +31,11 @@ type FieldTrie struct {
// NewFieldTrie is the constructor for the field trie data structure. It creates the corresponding
// trie according to the given parameters. Depending on whether the field is a basic/composite array
// which is either fixed/variable length, it will appropriately determine the trie.
func NewFieldTrie(field types.FieldIndex, dataType types.DataType, elements interface{}, length uint64) (*FieldTrie, error) {
func NewFieldTrie(field types.FieldIndex, fieldInfo types.DataType, elements interface{}, length uint64) (*FieldTrie, error) {
if elements == nil {
return &FieldTrie{
field: field,
dataType: dataType,
dataType: fieldInfo,
reference: stateutil.NewRef(1),
RWMutex: new(sync.RWMutex),
length: length,
@@ -48,10 +48,10 @@ func NewFieldTrie(field types.FieldIndex, dataType types.DataType, elements inte
return nil, err
}
if err := validateElements(field, dataType, elements, length); err != nil {
if err := validateElements(field, fieldInfo, elements, length); err != nil {
return nil, err
}
switch dataType {
switch fieldInfo {
case types.BasicArray:
fl, err := stateutil.ReturnTrieLayer(fieldRoots, length)
if err != nil {
@@ -60,7 +60,7 @@ func NewFieldTrie(field types.FieldIndex, dataType types.DataType, elements inte
return &FieldTrie{
fieldLayers: fl,
field: field,
dataType: dataType,
dataType: fieldInfo,
reference: stateutil.NewRef(1),
RWMutex: new(sync.RWMutex),
length: length,
@@ -70,14 +70,14 @@ func NewFieldTrie(field types.FieldIndex, dataType types.DataType, elements inte
return &FieldTrie{
fieldLayers: stateutil.ReturnTrieLayerVariable(fieldRoots, length),
field: field,
dataType: dataType,
dataType: fieldInfo,
reference: stateutil.NewRef(1),
RWMutex: new(sync.RWMutex),
length: length,
numOfElems: reflect.Indirect(reflect.ValueOf(elements)).Len(),
}, nil
default:
return nil, errors.Errorf("unrecognized data type in field map: %v", reflect.TypeOf(dataType).Name())
return nil, errors.Errorf("unrecognized data type in field map: %v", reflect.TypeOf(fieldInfo).Name())
}
}

View File

@@ -9,7 +9,6 @@ import (
customtypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native/custom-types"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native/types"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stateutil"
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
pmath "github.com/prysmaticlabs/prysm/v4/math"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
)
@@ -46,8 +45,8 @@ func (f *FieldTrie) validateIndices(idxs []uint64) error {
return nil
}
func validateElements(field types.FieldIndex, dataType types.DataType, elements interface{}, length uint64) error {
if dataType == types.CompressedArray {
func validateElements(field types.FieldIndex, fieldInfo types.DataType, elements interface{}, length uint64) error {
if fieldInfo == types.CompressedArray {
comLength, err := field.ElemsInChunk()
if err != nil {
return err
@@ -65,11 +64,11 @@ func validateElements(field types.FieldIndex, dataType types.DataType, elements
func fieldConverters(field types.FieldIndex, indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) {
switch field {
case types.BlockRoots:
return convertBlockRoots(indices, elements, convertAll)
return convert32ByteArrays[customtypes.BlockRoots](indices, elements, convertAll)
case types.StateRoots:
return convertStateRoots(indices, elements, convertAll)
return convert32ByteArrays[customtypes.StateRoots](indices, elements, convertAll)
case types.RandaoMixes:
return convertRandaoMixes(indices, elements, convertAll)
return convert32ByteArrays[customtypes.RandaoMixes](indices, elements, convertAll)
case types.Eth1DataVotes:
return convertEth1DataVotes(indices, elements, convertAll)
case types.Validators:
@@ -83,37 +82,13 @@ func fieldConverters(field types.FieldIndex, indices []uint64, elements interfac
}
}
func convertBlockRoots(indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) {
switch val := elements.(type) {
case [][]byte:
return handleByteArrays(val, indices, convertAll)
case *customtypes.BlockRoots:
return handle32ByteArrays(val[:], indices, convertAll)
default:
return nil, errors.Errorf("Incorrect type used for block roots")
}
}
func convertStateRoots(indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) {
switch val := elements.(type) {
case [][]byte:
return handleByteArrays(val, indices, convertAll)
case *customtypes.StateRoots:
return handle32ByteArrays(val[:], indices, convertAll)
default:
return nil, errors.Errorf("Incorrect type used for state roots")
}
}
func convertRandaoMixes(indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) {
switch val := elements.(type) {
case [][]byte:
return handleByteArrays(val, indices, convertAll)
case *customtypes.RandaoMixes:
return handle32ByteArrays(val[:], indices, convertAll)
default:
return nil, errors.Errorf("Incorrect type used for randao mixes")
func convert32ByteArrays[T ~[][32]byte](indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) {
val, ok := elements.(T)
if !ok {
var t T
return nil, errors.Errorf("Wanted type of %T but got %T", t, elements)
}
return handle32ByteArrays(val, indices, convertAll)
}
func convertEth1DataVotes(indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) {
@@ -148,34 +123,6 @@ func convertBalances(indices []uint64, elements interface{}, convertAll bool) ([
return handleBalanceSlice(val, indices, convertAll)
}
// handleByteArrays computes and returns byte arrays in a slice of root format.
func handleByteArrays(val [][]byte, indices []uint64, convertAll bool) ([][32]byte, error) {
length := len(indices)
if convertAll {
length = len(val)
}
roots := make([][32]byte, 0, length)
rootCreator := func(input []byte) {
newRoot := bytesutil.ToBytes32(input)
roots = append(roots, newRoot)
}
if convertAll {
for i := range val {
rootCreator(val[i])
}
return roots, nil
}
if len(val) > 0 {
for _, idx := range indices {
if idx > uint64(len(val))-1 {
return nil, fmt.Errorf("index %d greater than number of byte arrays %d", idx, len(val))
}
rootCreator(val[idx])
}
}
return roots, nil
}
// handle32ByteArrays computes and returns 32 byte arrays in a slice of root format.
func handle32ByteArrays(val [][32]byte, indices []uint64, convertAll bool) ([][32]byte, error) {
length := len(indices)

View File

@@ -4,6 +4,7 @@ import (
"testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/fieldtrie"
customtypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native/custom-types"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native/types"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stateutil"
"github.com/prysmaticlabs/prysm/v4/config/params"
@@ -16,11 +17,15 @@ import (
func TestFieldTrie_NewTrie(t *testing.T) {
newState, _ := util.DeterministicGenesisState(t, 40)
roots := newState.BlockRoots()
blockRoots := make([][32]byte, len(roots))
for i, r := range roots {
blockRoots[i] = [32]byte(r)
}
// 5 represents the enum value of state roots
trie, err := fieldtrie.NewFieldTrie(types.FieldIndex(5), types.BasicArray, newState.StateRoots(), uint64(params.BeaconConfig().SlotsPerHistoricalRoot))
trie, err := fieldtrie.NewFieldTrie(types.BlockRoots, types.BasicArray, customtypes.BlockRoots(blockRoots), uint64(params.BeaconConfig().SlotsPerHistoricalRoot))
require.NoError(t, err)
root, err := stateutil.RootsArrayHashTreeRoot(newState.StateRoots(), uint64(params.BeaconConfig().SlotsPerHistoricalRoot))
root, err := stateutil.RootsArrayHashTreeRoot(newState.BlockRoots(), uint64(params.BeaconConfig().SlotsPerHistoricalRoot))
require.NoError(t, err)
newRoot, err := trie.TrieRoot()
require.NoError(t, err)
@@ -28,7 +33,7 @@ func TestFieldTrie_NewTrie(t *testing.T) {
}
func TestFieldTrie_NewTrie_NilElements(t *testing.T) {
trie, err := fieldtrie.NewFieldTrie(types.FieldIndex(5), types.BasicArray, nil, 8234)
trie, err := fieldtrie.NewFieldTrie(types.BlockRoots, types.BasicArray, nil, 8234)
require.NoError(t, err)
_, err = trie.TrieRoot()
require.ErrorIs(t, err, fieldtrie.ErrEmptyFieldTrie)
@@ -36,8 +41,7 @@ func TestFieldTrie_NewTrie_NilElements(t *testing.T) {
func TestFieldTrie_RecomputeTrie(t *testing.T) {
newState, _ := util.DeterministicGenesisState(t, 32)
// 10 represents the enum value of validators
trie, err := fieldtrie.NewFieldTrie(types.FieldIndex(11), types.CompositeArray, newState.Validators(), params.BeaconConfig().ValidatorRegistryLimit)
trie, err := fieldtrie.NewFieldTrie(types.Validators, types.CompositeArray, newState.Validators(), params.BeaconConfig().ValidatorRegistryLimit)
require.NoError(t, err)
oldroot, err := trie.TrieRoot()
@@ -68,7 +72,7 @@ func TestFieldTrie_RecomputeTrie(t *testing.T) {
func TestFieldTrie_RecomputeTrie_CompressedArray(t *testing.T) {
newState, _ := util.DeterministicGenesisState(t, 32)
trie, err := fieldtrie.NewFieldTrie(types.FieldIndex(12), types.CompressedArray, newState.Balances(), stateutil.ValidatorLimitForBalancesChunks())
trie, err := fieldtrie.NewFieldTrie(types.Balances, types.CompressedArray, newState.Balances(), stateutil.ValidatorLimitForBalancesChunks())
require.NoError(t, err)
require.Equal(t, trie.Length(), stateutil.ValidatorLimitForBalancesChunks())
changedIdx := []uint64{4, 8}
@@ -85,14 +89,19 @@ func TestFieldTrie_RecomputeTrie_CompressedArray(t *testing.T) {
func TestNewFieldTrie_UnknownType(t *testing.T) {
newState, _ := util.DeterministicGenesisState(t, 32)
_, err := fieldtrie.NewFieldTrie(types.FieldIndex(12), 4, newState.Balances(), 32)
_, err := fieldtrie.NewFieldTrie(types.Balances, 4, newState.Balances(), 32)
require.ErrorContains(t, "unrecognized data type", err)
}
func TestFieldTrie_CopyTrieImmutable(t *testing.T) {
newState, _ := util.DeterministicGenesisState(t, 32)
// 12 represents the enum value of randao mixes.
trie, err := fieldtrie.NewFieldTrie(types.FieldIndex(13), types.BasicArray, newState.RandaoMixes(), uint64(params.BeaconConfig().EpochsPerHistoricalVector))
mixes := newState.RandaoMixes()
randaoMixes := make([][32]byte, len(mixes))
for i, r := range mixes {
randaoMixes[i] = [32]byte(r)
}
trie, err := fieldtrie.NewFieldTrie(types.RandaoMixes, types.BasicArray, customtypes.RandaoMixes(randaoMixes), uint64(params.BeaconConfig().EpochsPerHistoricalVector))
require.NoError(t, err)
newTrie := trie.CopyTrie()
@@ -100,10 +109,15 @@ func TestFieldTrie_CopyTrieImmutable(t *testing.T) {
changedIdx := []uint64{2, 29}
changedVals := [][32]byte{{'A', 'B'}, {'C', 'D'}}
require.NoError(t, newState.UpdateRandaoMixesAtIndex(changedIdx[0], changedVals[0][:]))
require.NoError(t, newState.UpdateRandaoMixesAtIndex(changedIdx[1], changedVals[1][:]))
require.NoError(t, newState.UpdateRandaoMixesAtIndex(changedIdx[0], changedVals[0]))
require.NoError(t, newState.UpdateRandaoMixesAtIndex(changedIdx[1], changedVals[1]))
root, err := trie.RecomputeTrie(changedIdx, newState.RandaoMixes())
mixes = newState.RandaoMixes()
randaoMixes = make([][32]byte, len(mixes))
for i, r := range mixes {
randaoMixes[i] = [32]byte(r)
}
root, err := trie.RecomputeTrie(changedIdx, customtypes.RandaoMixes(randaoMixes))
require.NoError(t, err)
newRoot, err := newTrie.TrieRoot()
require.NoError(t, err)
@@ -113,7 +127,7 @@ func TestFieldTrie_CopyTrieImmutable(t *testing.T) {
}
func TestFieldTrie_CopyAndTransferEmpty(t *testing.T) {
trie, err := fieldtrie.NewFieldTrie(types.FieldIndex(13), types.BasicArray, nil, uint64(params.BeaconConfig().EpochsPerHistoricalVector))
trie, err := fieldtrie.NewFieldTrie(types.RandaoMixes, types.BasicArray, nil, uint64(params.BeaconConfig().EpochsPerHistoricalVector))
require.NoError(t, err)
require.DeepEqual(t, trie, trie.CopyTrie())
@@ -123,7 +137,7 @@ func TestFieldTrie_CopyAndTransferEmpty(t *testing.T) {
func TestFieldTrie_TransferTrie(t *testing.T) {
newState, _ := util.DeterministicGenesisState(t, 32)
maxLength := (params.BeaconConfig().ValidatorRegistryLimit*8 + 31) / 32
trie, err := fieldtrie.NewFieldTrie(types.FieldIndex(12), types.CompressedArray, newState.Balances(), maxLength)
trie, err := fieldtrie.NewFieldTrie(types.Balances, types.CompressedArray, newState.Balances(), maxLength)
require.NoError(t, err)
oldRoot, err := trie.TrieRoot()
require.NoError(t, err)

View File

@@ -103,22 +103,12 @@ func TestFieldTrie_NativeState_fieldConvertersNative(t *testing.T) {
errMsg string
expectedLength int
}{
{
name: "BlockRoots [][]bytes",
args: &args{
field: types.FieldIndex(5),
indices: []uint64{},
elements: [][]byte{[]byte("dfsadfsadf")},
convertAll: true,
},
wantHex: []string{"0x6466736164667361646600000000000000000000000000000000000000000000"},
},
{
name: "BlockRoots customtypes.BlockRoots",
args: &args{
field: types.FieldIndex(5),
indices: []uint64{},
elements: &customtypes.BlockRoots{},
elements: customtypes.BlockRoots{},
convertAll: true,
},
wantHex: []string{"0x0000000000000000000000000000000000000000000000000000000000000000"},
@@ -133,34 +123,14 @@ func TestFieldTrie_NativeState_fieldConvertersNative(t *testing.T) {
convertAll: true,
},
wantHex: nil,
errMsg: "Incorrect type used for block roots",
},
{
name: "BlockRoots [][]bytes",
args: &args{
field: types.FieldIndex(5),
indices: []uint64{},
elements: [][]byte{[]byte("dfsadfsadf")},
convertAll: true,
},
wantHex: []string{"0x6466736164667361646600000000000000000000000000000000000000000000"},
},
{
name: "StateRoots [][]bytes",
args: &args{
field: types.FieldIndex(6),
indices: []uint64{},
elements: [][]byte{[]byte("dfsadfsadf")},
convertAll: true,
},
wantHex: []string{"0x6466736164667361646600000000000000000000000000000000000000000000"},
errMsg: "Wanted type of customtypes.BlockRoots",
},
{
name: "StateRoots customtypes.StateRoots",
args: &args{
field: types.FieldIndex(6),
indices: []uint64{},
elements: &customtypes.StateRoots{},
elements: customtypes.StateRoots{},
convertAll: true,
},
wantHex: []string{"0x0000000000000000000000000000000000000000000000000000000000000000"},
@@ -175,45 +145,25 @@ func TestFieldTrie_NativeState_fieldConvertersNative(t *testing.T) {
convertAll: true,
},
wantHex: nil,
errMsg: "Incorrect type used for state roots",
},
{
name: "StateRoots [][]bytes convert all false",
args: &args{
field: types.FieldIndex(6),
indices: []uint64{},
elements: [][]byte{[]byte("dfsadfsadf")},
convertAll: false,
},
wantHex: []string{"0x6466736164667361646600000000000000000000000000000000000000000000"},
errMsg: "Wanted type of customtypes.StateRoots",
},
{
name: "StateRoots customtypes.StateRoots convert all false",
args: &args{
field: types.FieldIndex(6),
indices: []uint64{},
elements: &customtypes.StateRoots{},
elements: customtypes.StateRoots{},
convertAll: false,
},
wantHex: []string{"0x0000000000000000000000000000000000000000000000000000000000000000"},
expectedLength: 8192,
},
{
name: "RandaoMixes [][]bytes",
args: &args{
field: types.FieldIndex(13),
indices: []uint64{},
elements: [][]byte{[]byte("dfsadfsadf")},
convertAll: true,
},
wantHex: []string{"0x6466736164667361646600000000000000000000000000000000000000000000"},
},
{
name: "RandaoMixes customtypes.RandaoMixes",
args: &args{
field: types.FieldIndex(13),
indices: []uint64{},
elements: &customtypes.RandaoMixes{},
elements: customtypes.RandaoMixes{},
convertAll: true,
},
wantHex: []string{"0x0000000000000000000000000000000000000000000000000000000000000000"},
@@ -228,7 +178,7 @@ func TestFieldTrie_NativeState_fieldConvertersNative(t *testing.T) {
convertAll: true,
},
wantHex: nil,
errMsg: "Incorrect type used for randao mixes",
errMsg: "Wanted type of customtypes.RandaoMixes",
},
{
name: "Eth1DataVotes type not found",

View File

@@ -237,7 +237,7 @@ type WriteOnlyBalances interface {
// WriteOnlyRandaoMixes defines a struct which only has write access to randao mixes methods.
type WriteOnlyRandaoMixes interface {
SetRandaoMixes(val [][]byte) error
UpdateRandaoMixesAtIndex(idx uint64, val []byte) error
UpdateRandaoMixesAtIndex(idx uint64, val [32]byte) error
}
// WriteOnlyCheckpoint defines a struct which only has write access to check point methods.

View File

@@ -18,6 +18,7 @@ go_library(
"getters_validator.go",
"getters_withdrawal.go",
"hasher.go",
"multi_value_slices.go",
"proofs.go",
"readonly_validator.go",
"setters_attestation.go",
@@ -49,11 +50,14 @@ go_library(
"//beacon-chain/state/state-native/custom-types:go_default_library",
"//beacon-chain/state/state-native/types:go_default_library",
"//beacon-chain/state/stateutil:go_default_library",
"//config/features:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//consensus-types:go_default_library",
"//consensus-types/blocks:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//consensus-types/primitives:go_default_library",
"//container/multi-value-slice:go_default_library",
"//container/slice:go_default_library",
"//crypto/hash:go_default_library",
"//encoding/bytesutil:go_default_library",
@@ -64,6 +68,8 @@ go_library(
"//runtime/version:go_default_library",
"//time/slots:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_prometheus_client_golang//prometheus:go_default_library",
"@com_github_prometheus_client_golang//prometheus/promauto:go_default_library",
"@com_github_prysmaticlabs_fastssz//:go_default_library",
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
"@io_opencensus_go//trace:go_default_library",
@@ -82,16 +88,22 @@ go_test(
"getters_validator_test.go",
"getters_withdrawal_test.go",
"hasher_test.go",
"mvslice_fuzz_test.go",
"proofs_test.go",
"readonly_validator_test.go",
"references_test.go",
"setters_attestation_test.go",
"setters_eth1_test.go",
"setters_misc_test.go",
"setters_participation_test.go",
"setters_validator_test.go",
"setters_withdrawal_test.go",
"state_fuzz_test.go",
"state_test.go",
"state_trie_test.go",
"types_test.go",
],
data = glob(["testdata/**"]),
embed = [":go_default_library"],
deps = [
"//beacon-chain/core/transition:go_default_library",
@@ -99,6 +111,7 @@ go_test(
"//beacon-chain/state/state-native/types:go_default_library",
"//beacon-chain/state/stateutil:go_default_library",
"//beacon-chain/state/testing:go_default_library",
"//config/features:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//consensus-types/blocks:go_default_library",

View File

@@ -11,6 +11,7 @@ import (
customtypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native/custom-types"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native/types"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stateutil"
"github.com/prysmaticlabs/prysm/v4/config/features"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
enginev1 "github.com/prysmaticlabs/prysm/v4/proto/engine/v1"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
@@ -25,16 +26,21 @@ type BeaconState struct {
slot primitives.Slot
fork *ethpb.Fork
latestBlockHeader *ethpb.BeaconBlockHeader
blockRoots *customtypes.BlockRoots
stateRoots *customtypes.StateRoots
blockRoots customtypes.BlockRoots
blockRootsMultiValue *MultiValueBlockRoots
stateRoots customtypes.StateRoots
stateRootsMultiValue *MultiValueStateRoots
historicalRoots customtypes.HistoricalRoots
historicalSummaries []*ethpb.HistoricalSummary
eth1Data *ethpb.Eth1Data
eth1DataVotes []*ethpb.Eth1Data
eth1DepositIndex uint64
validators []*ethpb.Validator
validatorsMultiValue *MultiValueValidators
balances []uint64
randaoMixes *customtypes.RandaoMixes
balancesMultiValue *MultiValueBalances
randaoMixes customtypes.RandaoMixes
randaoMixesMultiValue *MultiValueRandaoMixes
slashings []uint64
previousEpochAttestations []*ethpb.PendingAttestation
currentEpochAttestations []*ethpb.PendingAttestation
@@ -45,6 +51,7 @@ type BeaconState struct {
currentJustifiedCheckpoint *ethpb.Checkpoint
finalizedCheckpoint *ethpb.Checkpoint
inactivityScores []uint64
inactivityScoresMultiValue *MultiValueInactivityScores
currentSyncCommittee *ethpb.SyncCommittee
nextSyncCommittee *ethpb.SyncCommittee
latestExecutionPayloadHeader *enginev1.ExecutionPayloadHeader
@@ -53,6 +60,7 @@ type BeaconState struct {
nextWithdrawalIndex uint64
nextWithdrawalValidatorIndex primitives.ValidatorIndex
id uint64
lock sync.RWMutex
dirtyFields map[types.FieldIndex]bool
dirtyIndices map[types.FieldIndex][]uint64
@@ -70,8 +78,8 @@ type beaconStateMarshalable struct {
Slot primitives.Slot `json:"slot" yaml:"slot"`
Fork *ethpb.Fork `json:"fork" yaml:"fork"`
LatestBlockHeader *ethpb.BeaconBlockHeader `json:"latest_block_header" yaml:"latest_block_header"`
BlockRoots *customtypes.BlockRoots `json:"block_roots" yaml:"block_roots"`
StateRoots *customtypes.StateRoots `json:"state_roots" yaml:"state_roots"`
BlockRoots customtypes.BlockRoots `json:"block_roots" yaml:"block_roots"`
StateRoots customtypes.StateRoots `json:"state_roots" yaml:"state_roots"`
HistoricalRoots customtypes.HistoricalRoots `json:"historical_roots" yaml:"historical_roots"`
HistoricalSummaries []*ethpb.HistoricalSummary `json:"historical_summaries" yaml:"historical_summaries"`
Eth1Data *ethpb.Eth1Data `json:"eth_1_data" yaml:"eth_1_data"`
@@ -79,7 +87,7 @@ type beaconStateMarshalable struct {
Eth1DepositIndex uint64 `json:"eth_1_deposit_index" yaml:"eth_1_deposit_index"`
Validators []*ethpb.Validator `json:"validators" yaml:"validators"`
Balances []uint64 `json:"balances" yaml:"balances"`
RandaoMixes *customtypes.RandaoMixes `json:"randao_mixes" yaml:"randao_mixes"`
RandaoMixes customtypes.RandaoMixes `json:"randao_mixes" yaml:"randao_mixes"`
Slashings []uint64 `json:"slashings" yaml:"slashings"`
PreviousEpochAttestations []*ethpb.PendingAttestation `json:"previous_epoch_attestations" yaml:"previous_epoch_attestations"`
CurrentEpochAttestations []*ethpb.PendingAttestation `json:"current_epoch_attestations" yaml:"current_epoch_attestations"`
@@ -99,6 +107,29 @@ type beaconStateMarshalable struct {
}
func (b *BeaconState) MarshalJSON() ([]byte, error) {
var bRoots customtypes.BlockRoots
var sRoots customtypes.StateRoots
var mixes customtypes.RandaoMixes
var balances []uint64
var inactivityScores []uint64
var vals []*ethpb.Validator
if features.Get().EnableExperimentalState {
bRoots = b.blockRootsMultiValue.Value(b)
sRoots = b.stateRootsMultiValue.Value(b)
mixes = b.randaoMixesMultiValue.Value(b)
balances = b.balancesMultiValue.Value(b)
inactivityScores = b.inactivityScoresMultiValue.Value(b)
vals = b.validatorsMultiValue.Value(b)
} else {
bRoots = b.blockRoots
sRoots = b.stateRoots
mixes = b.randaoMixes
balances = b.balances
inactivityScores = b.inactivityScores
vals = b.validators
}
marshalable := &beaconStateMarshalable{
Version: b.version,
GenesisTime: b.genesisTime,
@@ -106,16 +137,16 @@ func (b *BeaconState) MarshalJSON() ([]byte, error) {
Slot: b.slot,
Fork: b.fork,
LatestBlockHeader: b.latestBlockHeader,
BlockRoots: b.blockRoots,
StateRoots: b.stateRoots,
BlockRoots: bRoots,
StateRoots: sRoots,
HistoricalRoots: b.historicalRoots,
HistoricalSummaries: b.historicalSummaries,
Eth1Data: b.eth1Data,
Eth1DataVotes: b.eth1DataVotes,
Eth1DepositIndex: b.eth1DepositIndex,
Validators: b.validators,
Balances: b.balances,
RandaoMixes: b.randaoMixes,
Validators: vals,
Balances: balances,
RandaoMixes: mixes,
Slashings: b.slashings,
PreviousEpochAttestations: b.previousEpochAttestations,
CurrentEpochAttestations: b.currentEpochAttestations,
@@ -125,7 +156,7 @@ func (b *BeaconState) MarshalJSON() ([]byte, error) {
PreviousJustifiedCheckpoint: b.previousJustifiedCheckpoint,
CurrentJustifiedCheckpoint: b.currentJustifiedCheckpoint,
FinalizedCheckpoint: b.finalizedCheckpoint,
InactivityScores: b.inactivityScores,
InactivityScores: inactivityScores,
CurrentSyncCommittee: b.currentSyncCommittee,
NextSyncCommittee: b.nextSyncCommittee,
LatestExecutionPayloadHeader: b.latestExecutionPayloadHeader,

View File

@@ -11,6 +11,7 @@ import (
customtypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native/custom-types"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native/types"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stateutil"
"github.com/prysmaticlabs/prysm/v4/config/features"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
enginev1 "github.com/prysmaticlabs/prysm/v4/proto/engine/v1"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
@@ -25,16 +26,21 @@ type BeaconState struct {
slot primitives.Slot
fork *ethpb.Fork
latestBlockHeader *ethpb.BeaconBlockHeader
blockRoots *customtypes.BlockRoots
stateRoots *customtypes.StateRoots
blockRoots customtypes.BlockRoots
blockRootsMultiValue *MultiValueBlockRoots
stateRoots customtypes.StateRoots
stateRootsMultiValue *MultiValueStateRoots
historicalRoots customtypes.HistoricalRoots
historicalSummaries []*ethpb.HistoricalSummary
eth1Data *ethpb.Eth1Data
eth1DataVotes []*ethpb.Eth1Data
eth1DepositIndex uint64
validators []*ethpb.Validator
validatorsMultiValue *MultiValueValidators
balances []uint64
randaoMixes *customtypes.RandaoMixes
balancesMultiValue *MultiValueBalances
randaoMixes customtypes.RandaoMixes
randaoMixesMultiValue *MultiValueRandaoMixes
slashings []uint64
previousEpochAttestations []*ethpb.PendingAttestation
currentEpochAttestations []*ethpb.PendingAttestation
@@ -45,6 +51,7 @@ type BeaconState struct {
currentJustifiedCheckpoint *ethpb.Checkpoint
finalizedCheckpoint *ethpb.Checkpoint
inactivityScores []uint64
inactivityScoresMultiValue *MultiValueInactivityScores
currentSyncCommittee *ethpb.SyncCommittee
nextSyncCommittee *ethpb.SyncCommittee
latestExecutionPayloadHeader *enginev1.ExecutionPayloadHeader
@@ -53,6 +60,7 @@ type BeaconState struct {
nextWithdrawalIndex uint64
nextWithdrawalValidatorIndex primitives.ValidatorIndex
id uint64
lock sync.RWMutex
dirtyFields map[types.FieldIndex]bool
dirtyIndices map[types.FieldIndex][]uint64
@@ -70,8 +78,8 @@ type beaconStateMarshalable struct {
Slot primitives.Slot `json:"slot" yaml:"slot"`
Fork *ethpb.Fork `json:"fork" yaml:"fork"`
LatestBlockHeader *ethpb.BeaconBlockHeader `json:"latest_block_header" yaml:"latest_block_header"`
BlockRoots *customtypes.BlockRoots `json:"block_roots" yaml:"block_roots"`
StateRoots *customtypes.StateRoots `json:"state_roots" yaml:"state_roots"`
BlockRoots customtypes.BlockRoots `json:"block_roots" yaml:"block_roots"`
StateRoots customtypes.StateRoots `json:"state_roots" yaml:"state_roots"`
HistoricalRoots customtypes.HistoricalRoots `json:"historical_roots" yaml:"historical_roots"`
HistoricalSummaries []*ethpb.HistoricalSummary `json:"historical_summaries" yaml:"historical_summaries"`
Eth1Data *ethpb.Eth1Data `json:"eth_1_data" yaml:"eth_1_data"`
@@ -79,7 +87,7 @@ type beaconStateMarshalable struct {
Eth1DepositIndex uint64 `json:"eth_1_deposit_index" yaml:"eth_1_deposit_index"`
Validators []*ethpb.Validator `json:"validators" yaml:"validators"`
Balances []uint64 `json:"balances" yaml:"balances"`
RandaoMixes *customtypes.RandaoMixes `json:"randao_mixes" yaml:"randao_mixes"`
RandaoMixes customtypes.RandaoMixes `json:"randao_mixes" yaml:"randao_mixes"`
Slashings []uint64 `json:"slashings" yaml:"slashings"`
PreviousEpochAttestations []*ethpb.PendingAttestation `json:"previous_epoch_attestations" yaml:"previous_epoch_attestations"`
CurrentEpochAttestations []*ethpb.PendingAttestation `json:"current_epoch_attestations" yaml:"current_epoch_attestations"`
@@ -99,6 +107,29 @@ type beaconStateMarshalable struct {
}
func (b *BeaconState) MarshalJSON() ([]byte, error) {
var bRoots customtypes.BlockRoots
var sRoots customtypes.StateRoots
var mixes customtypes.RandaoMixes
var balances []uint64
var inactivityScores []uint64
var vals []*ethpb.Validator
if features.Get().EnableExperimentalState {
bRoots = b.blockRootsMultiValue.Value(b)
sRoots = b.stateRootsMultiValue.Value(b)
mixes = b.randaoMixesMultiValue.Value(b)
balances = b.balancesMultiValue.Value(b)
inactivityScores = b.inactivityScoresMultiValue.Value(b)
vals = b.validatorsMultiValue.Value(b)
} else {
bRoots = b.blockRoots
sRoots = b.stateRoots
mixes = b.randaoMixes
balances = b.balances
inactivityScores = b.inactivityScores
vals = b.validators
}
marshalable := &beaconStateMarshalable{
Version: b.version,
GenesisTime: b.genesisTime,
@@ -106,16 +137,16 @@ func (b *BeaconState) MarshalJSON() ([]byte, error) {
Slot: b.slot,
Fork: b.fork,
LatestBlockHeader: b.latestBlockHeader,
BlockRoots: b.blockRoots,
StateRoots: b.stateRoots,
BlockRoots: bRoots,
StateRoots: sRoots,
HistoricalRoots: b.historicalRoots,
HistoricalSummaries: b.historicalSummaries,
Eth1Data: b.eth1Data,
Eth1DataVotes: b.eth1DataVotes,
Eth1DepositIndex: b.eth1DepositIndex,
Validators: b.validators,
Balances: b.balances,
RandaoMixes: b.randaoMixes,
Validators: vals,
Balances: balances,
RandaoMixes: mixes,
Slashings: b.slashings,
PreviousEpochAttestations: b.previousEpochAttestations,
CurrentEpochAttestations: b.currentEpochAttestations,
@@ -125,7 +156,7 @@ func (b *BeaconState) MarshalJSON() ([]byte, error) {
PreviousJustifiedCheckpoint: b.previousJustifiedCheckpoint,
CurrentJustifiedCheckpoint: b.currentJustifiedCheckpoint,
FinalizedCheckpoint: b.finalizedCheckpoint,
InactivityScores: b.inactivityScores,
InactivityScores: inactivityScores,
CurrentSyncCommittee: b.currentSyncCommittee,
NextSyncCommittee: b.nextSyncCommittee,
LatestExecutionPayloadHeader: b.latestExecutionPayloadHeader,

View File

@@ -7,12 +7,12 @@ import (
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
)
var _ fssz.HashRoot = (BlockRoots)([fieldparams.BlockRootsLength][32]byte{})
var _ fssz.HashRoot = (BlockRoots)([][32]byte{})
var _ fssz.Marshaler = (*BlockRoots)(nil)
var _ fssz.Unmarshaler = (*BlockRoots)(nil)
// BlockRoots represents block roots of the beacon state.
type BlockRoots [fieldparams.BlockRootsLength][32]byte
type BlockRoots [][32]byte
// HashTreeRoot returns calculated hash root.
func (r BlockRoots) HashTreeRoot() ([32]byte, error) {
@@ -35,7 +35,7 @@ func (r *BlockRoots) UnmarshalSSZ(buf []byte) error {
return fmt.Errorf("expected buffer of length %d received %d", r.SizeSSZ(), len(buf))
}
var roots BlockRoots
roots := BlockRoots(make([][32]byte, fieldparams.BlockRootsLength))
for i := range roots {
copy(roots[i][:], buf[i*32:(i+1)*32])
}
@@ -44,7 +44,7 @@ func (r *BlockRoots) UnmarshalSSZ(buf []byte) error {
}
// MarshalSSZTo marshals BlockRoots with the provided byte slice.
func (r *BlockRoots) MarshalSSZTo(dst []byte) ([]byte, error) {
func (r BlockRoots) MarshalSSZTo(dst []byte) ([]byte, error) {
marshalled, err := r.MarshalSSZ()
if err != nil {
return nil, err
@@ -53,7 +53,7 @@ func (r *BlockRoots) MarshalSSZTo(dst []byte) ([]byte, error) {
}
// MarshalSSZ marshals BlockRoots into a serialized object.
func (r *BlockRoots) MarshalSSZ() ([]byte, error) {
func (r BlockRoots) MarshalSSZ() ([]byte, error) {
marshalled := make([]byte, fieldparams.BlockRootsLength*32)
for i, r32 := range r {
for j, rr := range r32 {
@@ -64,12 +64,13 @@ func (r *BlockRoots) MarshalSSZ() ([]byte, error) {
}
// SizeSSZ returns the size of the serialized object.
func (_ *BlockRoots) SizeSSZ() int {
func (_ BlockRoots) SizeSSZ() int {
return fieldparams.BlockRootsLength * 32
}
// Slice converts a customtypes.BlockRoots object into a 2D byte slice.
func (r *BlockRoots) Slice() [][]byte {
// Each item in the slice is a copy of the original item.
func (r BlockRoots) Slice() [][]byte {
if r == nil {
return nil
}

View File

@@ -8,14 +8,6 @@ import (
"github.com/prysmaticlabs/prysm/v4/testing/assert"
)
func TestBlockRoots_Casting(t *testing.T) {
var b [fieldparams.BlockRootsLength][32]byte
d := BlockRoots(b)
if !reflect.DeepEqual([fieldparams.BlockRootsLength][32]byte(d), b) {
t.Errorf("Unequal: %v = %v", d, b)
}
}
func TestBlockRoots_UnmarshalSSZ(t *testing.T) {
t.Run("Ok", func(t *testing.T) {
d := BlockRoots{}
@@ -70,7 +62,7 @@ func TestBlockRoots_MarshalSSZTo(t *testing.T) {
}
func TestBlockRoots_MarshalSSZ(t *testing.T) {
d := BlockRoots{}
d := BlockRoots(make([][32]byte, fieldparams.BlockRootsLength))
d[0] = [32]byte{'f', 'o', 'o'}
d[1] = [32]byte{'b', 'a', 'r'}
b, err := d.MarshalSSZ()
@@ -94,7 +86,7 @@ func TestBlockRoots_SizeSSZ(t *testing.T) {
func TestBlockRoots_Slice(t *testing.T) {
a, b, c := [32]byte{'a'}, [32]byte{'b'}, [32]byte{'c'}
roots := BlockRoots{}
roots := BlockRoots(make([][32]byte, fieldparams.BlockRootsLength))
roots[1] = a
roots[10] = b
roots[100] = c

View File

@@ -43,7 +43,7 @@ func (r *HistoricalRoots) UnmarshalSSZ(buf []byte) error {
}
// MarshalSSZTo marshals HistoricalRoots with the provided byte slice.
func (r *HistoricalRoots) MarshalSSZTo(dst []byte) ([]byte, error) {
func (r HistoricalRoots) MarshalSSZTo(dst []byte) ([]byte, error) {
marshalled, err := r.MarshalSSZ()
if err != nil {
return nil, err
@@ -52,9 +52,9 @@ func (r *HistoricalRoots) MarshalSSZTo(dst []byte) ([]byte, error) {
}
// MarshalSSZ marshals HistoricalRoots into a serialized object.
func (r *HistoricalRoots) MarshalSSZ() ([]byte, error) {
marshalled := make([]byte, len(*r)*32)
for i, r32 := range *r {
func (r HistoricalRoots) MarshalSSZ() ([]byte, error) {
marshalled := make([]byte, len(r)*32)
for i, r32 := range r {
for j, rr := range r32 {
marshalled[i*32+j] = rr
}
@@ -63,17 +63,17 @@ func (r *HistoricalRoots) MarshalSSZ() ([]byte, error) {
}
// SizeSSZ returns the size of the serialized object.
func (r *HistoricalRoots) SizeSSZ() int {
return len(*r) * 32
func (r HistoricalRoots) SizeSSZ() int {
return len(r) * 32
}
// Slice converts a customtypes.HistoricalRoots object into a 2D byte slice.
func (r *HistoricalRoots) Slice() [][]byte {
func (r HistoricalRoots) Slice() [][]byte {
if r == nil {
return nil
}
hRoots := make([][]byte, len(*r))
for i, root := range *r {
hRoots := make([][]byte, len(r))
for i, root := range r {
tmp := root
hRoots[i] = tmp[:]
}

View File

@@ -7,12 +7,12 @@ import (
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
)
var _ fssz.HashRoot = (RandaoMixes)([fieldparams.RandaoMixesLength][32]byte{})
var _ fssz.HashRoot = (RandaoMixes)([][32]byte{})
var _ fssz.Marshaler = (*RandaoMixes)(nil)
var _ fssz.Unmarshaler = (*RandaoMixes)(nil)
// RandaoMixes represents RANDAO mixes of the beacon state.
type RandaoMixes [fieldparams.RandaoMixesLength][32]byte
type RandaoMixes [][32]byte
// HashTreeRoot returns calculated hash root.
func (r RandaoMixes) HashTreeRoot() ([32]byte, error) {
@@ -35,7 +35,7 @@ func (r *RandaoMixes) UnmarshalSSZ(buf []byte) error {
return fmt.Errorf("expected buffer of length %d received %d", r.SizeSSZ(), len(buf))
}
var roots RandaoMixes
roots := RandaoMixes(make([][32]byte, fieldparams.RandaoMixesLength))
for i := range roots {
copy(roots[i][:], buf[i*32:(i+1)*32])
}
@@ -44,7 +44,7 @@ func (r *RandaoMixes) UnmarshalSSZ(buf []byte) error {
}
// MarshalSSZTo marshals RandaoMixes with the provided byte slice.
func (r *RandaoMixes) MarshalSSZTo(dst []byte) ([]byte, error) {
func (r RandaoMixes) MarshalSSZTo(dst []byte) ([]byte, error) {
marshalled, err := r.MarshalSSZ()
if err != nil {
return nil, err
@@ -53,7 +53,7 @@ func (r *RandaoMixes) MarshalSSZTo(dst []byte) ([]byte, error) {
}
// MarshalSSZ marshals RandaoMixes into a serialized object.
func (r *RandaoMixes) MarshalSSZ() ([]byte, error) {
func (r RandaoMixes) MarshalSSZ() ([]byte, error) {
marshalled := make([]byte, fieldparams.RandaoMixesLength*32)
for i, r32 := range r {
for j, rr := range r32 {
@@ -64,12 +64,13 @@ func (r *RandaoMixes) MarshalSSZ() ([]byte, error) {
}
// SizeSSZ returns the size of the serialized object.
func (_ *RandaoMixes) SizeSSZ() int {
func (_ RandaoMixes) SizeSSZ() int {
return fieldparams.RandaoMixesLength * 32
}
// Slice converts a customtypes.RandaoMixes object into a 2D byte slice.
func (r *RandaoMixes) Slice() [][]byte {
// Each item in the slice is a copy of the original item.
func (r RandaoMixes) Slice() [][]byte {
if r == nil {
return nil
}

View File

@@ -8,14 +8,6 @@ import (
"github.com/prysmaticlabs/prysm/v4/testing/assert"
)
func TestRandaoMixes_Casting(t *testing.T) {
var b [fieldparams.RandaoMixesLength][32]byte
d := RandaoMixes(b)
if !reflect.DeepEqual([fieldparams.RandaoMixesLength][32]byte(d), b) {
t.Errorf("Unequal: %v = %v", d, b)
}
}
func TestRandaoMixes_UnmarshalSSZ(t *testing.T) {
t.Run("Ok", func(t *testing.T) {
d := RandaoMixes{}
@@ -70,7 +62,7 @@ func TestRandaoMixes_MarshalSSZTo(t *testing.T) {
}
func TestRandaoMixes_MarshalSSZ(t *testing.T) {
d := RandaoMixes{}
d := RandaoMixes(make([][32]byte, fieldparams.RandaoMixesLength))
d[0] = [32]byte{'f', 'o', 'o'}
d[1] = [32]byte{'b', 'a', 'r'}
b, err := d.MarshalSSZ()
@@ -94,7 +86,7 @@ func TestRandaoMixes_SizeSSZ(t *testing.T) {
func TestRandaoMixes_Slice(t *testing.T) {
a, b, c := [32]byte{'a'}, [32]byte{'b'}, [32]byte{'c'}
roots := RandaoMixes{}
roots := RandaoMixes(make([][32]byte, fieldparams.RandaoMixesLength))
roots[1] = a
roots[10] = b
roots[100] = c

View File

@@ -7,12 +7,12 @@ import (
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
)
var _ fssz.HashRoot = (StateRoots)([fieldparams.StateRootsLength][32]byte{})
var _ fssz.HashRoot = (StateRoots)([][32]byte{})
var _ fssz.Marshaler = (*StateRoots)(nil)
var _ fssz.Unmarshaler = (*StateRoots)(nil)
// StateRoots represents block roots of the beacon state.
type StateRoots [fieldparams.StateRootsLength][32]byte
type StateRoots [][32]byte
// HashTreeRoot returns calculated hash root.
func (r StateRoots) HashTreeRoot() ([32]byte, error) {
@@ -35,7 +35,7 @@ func (r *StateRoots) UnmarshalSSZ(buf []byte) error {
return fmt.Errorf("expected buffer of length %d received %d", r.SizeSSZ(), len(buf))
}
var roots StateRoots
roots := StateRoots(make([][32]byte, fieldparams.StateRootsLength))
for i := range roots {
copy(roots[i][:], buf[i*32:(i+1)*32])
}
@@ -44,7 +44,7 @@ func (r *StateRoots) UnmarshalSSZ(buf []byte) error {
}
// MarshalSSZTo marshals StateRoots with the provided byte slice.
func (r *StateRoots) MarshalSSZTo(dst []byte) ([]byte, error) {
func (r StateRoots) MarshalSSZTo(dst []byte) ([]byte, error) {
marshalled, err := r.MarshalSSZ()
if err != nil {
return nil, err
@@ -53,7 +53,7 @@ func (r *StateRoots) MarshalSSZTo(dst []byte) ([]byte, error) {
}
// MarshalSSZ marshals StateRoots into a serialized object.
func (r *StateRoots) MarshalSSZ() ([]byte, error) {
func (r StateRoots) MarshalSSZ() ([]byte, error) {
marshalled := make([]byte, fieldparams.StateRootsLength*32)
for i, r32 := range r {
for j, rr := range r32 {
@@ -64,12 +64,13 @@ func (r *StateRoots) MarshalSSZ() ([]byte, error) {
}
// SizeSSZ returns the size of the serialized object.
func (_ *StateRoots) SizeSSZ() int {
func (_ StateRoots) SizeSSZ() int {
return fieldparams.StateRootsLength * 32
}
// Slice converts a customtypes.StateRoots object into a 2D byte slice.
func (r *StateRoots) Slice() [][]byte {
// Each item in the slice is a copy of the original item.
func (r StateRoots) Slice() [][]byte {
if r == nil {
return nil
}

View File

@@ -8,14 +8,6 @@ import (
"github.com/prysmaticlabs/prysm/v4/testing/assert"
)
func TestStateRoots_Casting(t *testing.T) {
var b [fieldparams.StateRootsLength][32]byte
d := StateRoots(b)
if !reflect.DeepEqual([fieldparams.StateRootsLength][32]byte(d), b) {
t.Errorf("Unequal: %v = %v", d, b)
}
}
func TestStateRoots_UnmarshalSSZ(t *testing.T) {
t.Run("Ok", func(t *testing.T) {
d := StateRoots{}
@@ -70,7 +62,7 @@ func TestStateRoots_MarshalSSZTo(t *testing.T) {
}
func TestStateRoots_MarshalSSZ(t *testing.T) {
d := StateRoots{}
d := StateRoots(make([][32]byte, fieldparams.StateRootsLength))
d[0] = [32]byte{'f', 'o', 'o'}
d[1] = [32]byte{'b', 'a', 'r'}
b, err := d.MarshalSSZ()
@@ -94,7 +86,7 @@ func TestStateRoots_SizeSSZ(t *testing.T) {
func TestStateRoots_Slice(t *testing.T) {
a, b, c := [32]byte{'a'}, [32]byte{'b'}, [32]byte{'c'}
roots := StateRoots{}
roots := StateRoots(make([][32]byte, fieldparams.StateRootsLength))
roots[1] = a
roots[10] = b
roots[100] = c

View File

@@ -1,8 +1,10 @@
package state_native
import (
"fmt"
"github.com/pkg/errors"
customtypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native/custom-types"
"github.com/prysmaticlabs/prysm/v4/config/features"
consensus_types "github.com/prysmaticlabs/prysm/v4/consensus-types"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
)
@@ -45,26 +47,46 @@ func (b *BeaconState) latestBlockHeaderVal() *ethpb.BeaconBlockHeader {
// BlockRoots kept track of in the beacon state.
func (b *BeaconState) BlockRoots() [][]byte {
if b.blockRoots == nil {
return nil
}
b.lock.RLock()
defer b.lock.RUnlock()
return b.blockRoots.Slice()
roots := b.blockRootsVal()
if roots == nil {
return nil
}
return roots.Slice()
}
func (b *BeaconState) blockRootsVal() customtypes.BlockRoots {
if features.Get().EnableExperimentalState {
if b.blockRootsMultiValue == nil {
return nil
}
return b.blockRootsMultiValue.Value(b)
}
return b.blockRoots
}
// BlockRootAtIndex retrieves a specific block root based on an
// input index value.
func (b *BeaconState) BlockRootAtIndex(idx uint64) ([]byte, error) {
if b.blockRoots == nil {
return []byte{}, nil
}
b.lock.RLock()
defer b.lock.RUnlock()
if features.Get().EnableExperimentalState {
if b.blockRootsMultiValue == nil {
return []byte{}, nil
}
r, err := b.blockRootsMultiValue.At(b, idx)
if err != nil {
return nil, err
}
return r[:], nil
}
if b.blockRoots == nil {
return []byte{}, nil
}
r, err := b.blockRootAtIndex(idx)
if err != nil {
return nil, err
@@ -77,7 +99,7 @@ func (b *BeaconState) BlockRootAtIndex(idx uint64) ([]byte, error) {
// This assumes that a lock is already held on BeaconState.
func (b *BeaconState) blockRootAtIndex(idx uint64) ([32]byte, error) {
if uint64(len(b.blockRoots)) <= idx {
return [32]byte{}, fmt.Errorf("index %d out of range", idx)
return [32]byte{}, errors.Wrapf(consensus_types.ErrOutOfBounds, "block root index %d does not exist", idx)
}
return b.blockRoots[idx], nil
}

View File

@@ -6,6 +6,11 @@ import (
"github.com/prysmaticlabs/prysm/v4/runtime/version"
)
// Id is the identifier of the beacon state.
func (b *BeaconState) Id() uint64 {
return b.id
}
// GenesisTime of the beacon state as a uint64.
func (b *BeaconState) GenesisTime() uint64 {
b.lock.RLock()
@@ -79,16 +84,6 @@ func (b *BeaconState) HistoricalRoots() ([][]byte, error) {
return b.historicalRoots.Slice(), nil
}
// balancesLength returns the length of the balances slice.
// This assumes that a lock is already held on BeaconState.
func (b *BeaconState) balancesLength() int {
if b.balances == nil {
return 0
}
return len(b.balances)
}
// HistoricalSummaries of the beacon state.
func (b *BeaconState) HistoricalSummaries() ([]*ethpb.HistoricalSummary, error) {
if b.version < version.Capella {

View File

@@ -3,6 +3,7 @@ package state_native
import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/time"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stateutil"
"github.com/prysmaticlabs/prysm/v4/config/features"
"github.com/prysmaticlabs/prysm/v4/runtime/version"
)
@@ -56,7 +57,11 @@ func (b *BeaconState) UnrealizedCheckpointBalances() (uint64, uint64, uint64, er
return 0, 0, 0, ErrNilParticipation
}
return stateutil.UnrealizedCheckpointBalances(cp, pp, b.validators, currentEpoch)
if features.Get().EnableExperimentalState {
return stateutil.UnrealizedCheckpointBalances(cp, pp, b.validatorsVal(), currentEpoch)
} else {
return stateutil.UnrealizedCheckpointBalances(cp, pp, b.validators, currentEpoch)
}
}
// currentEpochParticipationVal corresponding to participation bits on the beacon chain.

View File

@@ -1,31 +1,54 @@
package state_native
import (
"fmt"
"github.com/pkg/errors"
customtypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native/custom-types"
"github.com/prysmaticlabs/prysm/v4/config/features"
consensus_types "github.com/prysmaticlabs/prysm/v4/consensus-types"
)
// RandaoMixes of block proposers on the beacon chain.
func (b *BeaconState) RandaoMixes() [][]byte {
if b.randaoMixes == nil {
return nil
}
b.lock.RLock()
defer b.lock.RUnlock()
return b.randaoMixes.Slice()
mixes := b.randaoMixesVal()
if mixes == nil {
return nil
}
return mixes.Slice()
}
func (b *BeaconState) randaoMixesVal() customtypes.RandaoMixes {
if features.Get().EnableExperimentalState {
if b.randaoMixesMultiValue == nil {
return nil
}
return b.randaoMixesMultiValue.Value(b)
}
return b.randaoMixes
}
// RandaoMixAtIndex retrieves a specific block root based on an
// input index value.
func (b *BeaconState) RandaoMixAtIndex(idx uint64) ([]byte, error) {
if b.randaoMixes == nil {
return nil, nil
}
b.lock.RLock()
defer b.lock.RUnlock()
if features.Get().EnableExperimentalState {
if b.randaoMixesMultiValue == nil {
return nil, nil
}
r, err := b.randaoMixesMultiValue.At(b, idx)
if err != nil {
return nil, err
}
return r[:], nil
}
if b.randaoMixes == nil {
return nil, nil
}
m, err := b.randaoMixAtIndex(idx)
if err != nil {
return nil, err
@@ -38,7 +61,7 @@ func (b *BeaconState) RandaoMixAtIndex(idx uint64) ([]byte, error) {
// This assumes that a lock is already held on BeaconState.
func (b *BeaconState) randaoMixAtIndex(idx uint64) ([32]byte, error) {
if uint64(len(b.randaoMixes)) <= idx {
return [32]byte{}, fmt.Errorf("index %d out of range", idx)
return [32]byte{}, errors.Wrapf(consensus_types.ErrOutOfBounds, "randao mix index %d does not exist", idx)
}
return b.randaoMixes[idx], nil
@@ -46,22 +69,17 @@ func (b *BeaconState) randaoMixAtIndex(idx uint64) ([32]byte, error) {
// RandaoMixesLength returns the length of the randao mixes slice.
func (b *BeaconState) RandaoMixesLength() int {
if b.randaoMixes == nil {
return 0
}
b.lock.RLock()
defer b.lock.RUnlock()
return b.randaoMixesLength()
}
// randaoMixesLength returns the length of the randao mixes slice.
// This assumes that a lock is already held on BeaconState.
func (b *BeaconState) randaoMixesLength() int {
if features.Get().EnableExperimentalState {
if b.randaoMixesMultiValue == nil {
return 0
}
return b.randaoMixesMultiValue.Len(b)
}
if b.randaoMixes == nil {
return 0
}
return len(b.randaoMixes)
}

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