Compare commits

...

62 Commits

Author SHA1 Message Date
Preston Van Loon
f4681fde19 windows: Fix build after PR 12293 (#12296) 2023-04-17 20:43:40 +00:00
Preston Van Loon
0c7292b85b prysmctl: Add support for writing signed validator exits to disk (#12262)
* prysmctl: Add support for writing signed validator exits to disk

* Add dir suffix

* Add test to ensure no broadcast call was made

---------

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2023-04-17 18:01:13 +00:00
james-prysm
10b438e2c8 Keymanager fixes for bad file writes (#12284)
* WIP changes for keymanager

* WIP fix

* WIP needs unit tests

* fixing order

* adding unit test

* fixing linter

* updating unit tests and creating more reusable functions

* making accountStore copy method part of struct

* Update validator/keymanager/local/delete_test.go

* Update validator/keymanager/local/delete.go

* Update validator/keymanager/local/delete.go

Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com>

* Update validator/keymanager/local/import.go

Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com>

* Update validator/keymanager/local/delete.go

Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com>

* Update validator/keymanager/local/delete.go

Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com>

* Update validator/keymanager/local/import.go

Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com>

* Update validator/keymanager/local/import.go

Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com>

* Update validator/keymanager/local/delete.go

Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com>

* addressing suggestion of not reinitializing from reading the file but instead update the information based on memory on hand

* Update validator/accounts/wallet_create.go

Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com>

* adding changes based on suggestions

* making logs more consistent

* fixing linting

---------

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>
Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com>
2023-04-17 12:08:27 -05:00
Nishant Das
e2386cfb11 Fix Attester Slashing Validation In Gossip (#12295)
* fix slashing checks

* fix to make it more performant

* gaz

* fix up

* potuz's comment

* potuz's comment

* fix cache

* change index in test for better case

* gaz

---------

Co-authored-by: Potuz <potuz@prysmaticlabs.com>
2023-04-17 15:35:38 +00:00
Radosław Kapka
898cb0b512 Deflake TestWaitForActivation_AccountsChanged (#12282)
Co-authored-by: terencechain <terence@prysmaticlabs.com>
2023-04-17 15:04:42 +00:00
Sammy Rosso
6944d22ce3 Add support for engine_exchangeCapabilities (#12224)
* Add call to engine_exchangeCapabilities

* Fix unused import

* Cleanup + tests

* Warning only when needed

* Add Radek' feedback
2023-04-17 12:55:22 +00:00
Nishant Das
1eb00866ea Add License For Vendored Dependency (#12294) 2023-04-17 08:16:47 +00:00
Nishant Das
4862d57b13 Fix Broken Dependency (#12293)
* vendor in library

* comment

* lint

* lint
2023-04-17 12:22:34 +08:00
Potuz
191b0c4652 Correctly use Gwei to compare builder bid value (#12290)
* Correctly use Gwei to compare builder bid value

* Minimal 1gwei for TestProduceBlindedBlock

---------

Co-authored-by: terence tsao <terence@prysmaticlabs.com>
2023-04-16 16:47:51 +08:00
kasey
c09977d8a8 support modifying genesis.json for capella (#12283)
Co-authored-by: kasey <kasey@users.noreply.github.com>
2023-04-14 20:32:40 +00:00
Nishant Das
52d72c989e Check that Builder Is Configured (#12279)
* add configured check

* tests

---------

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2023-04-14 10:21:46 +00:00
Justin Traglia
9f7711e74a Enable misspell linter & fix findings (#12272)
Co-authored-by: Radosław Kapka <rkapka@wp.pl>
2023-04-14 10:03:11 +00:00
Nishant Das
f376427add fix panic (#12277) 2023-04-13 22:42:57 -07:00
kasey
ff1b03ab13 prysmctl using the same genesis func as e2e (#12268)
* prysmctl using the same genesis func as e2e

* add whitespace to genesis.json for readability

* fix typo in fork name

* don't require validator count if deposits given

* add gosec exception

* the other nosec :(

* appease deepsource

* fix comments on renamed public value/func

---------

Co-authored-by: kasey <kasey@users.noreply.github.com>
2023-04-13 17:19:06 +00:00
Potuz
5fdd4e9148 Add prepare-all-payloads flag (#12260)
* Add prepare-all-payloads flag

* add unit tests

* do not use the nsc

---------

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2023-04-13 14:47:13 +00:00
Patrice Vignola
80e26143eb Add REST API endpoint for beacon chain client's GetChainHead (#12245)
* Add REST API endpoint for beacon chain client's GetChainHead

* Remove unused parameters

---------

Co-authored-by: Radosław Kapka <rkapka@wp.pl>
2023-04-13 11:42:59 +00:00
Nishant Das
75338dd83d Fix User Agent In Builder Client (#12264) 2023-04-13 03:12:51 +00:00
terencechain
99eebe9bac Fix capella unblind block with bls field (#12263) 2023-04-12 18:47:34 -07:00
keithchew
6b1efff4e8 allow setting GOMAXPROCS from environment variable (#12256)
* allow setting GOMAXPROCS from environment variable

* remove unused import
2023-04-10 23:28:48 -04:00
Preston Van Loon
763e9e3361 Update go to version 1.19.8 (#12238)
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2023-04-10 19:03:24 +00:00
Nishant Das
37182168e3 Fix Deadlock in StreamChainHead (#12250)
* fix it possibly

* buffer it more

* fix test
2023-04-07 15:41:31 -05:00
terencechain
0325741318 Add orphaned operations to the appropriate pools in saveOrphanedOps() and mark included slashings in prunePostBlockOperationPools(). (#12249)
Co-authored-by: james-prysm <90280386+james-prysm@users.noreply.github.com>
2023-04-06 16:26:01 -05:00
Preston Van Loon
150e8aa14d Remove unused beacon-chain/server binary (#12241)
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2023-04-06 20:56:55 +00:00
kasey
f4307a902c build tag to exclude mainnet genesis from prysmctl (#12244)
Co-authored-by: Kasey Kirkham <kasey@users.noreply.github.com>
Co-authored-by: james-prysm <90280386+james-prysm@users.noreply.github.com>
2023-04-06 19:45:35 +00:00
james-prysm
d257ef1742 Builder: fix nil panic edgecase (#12236)
* adding fix for buildervalue nil

* fixing linting

* changing based on review comment

* editing based on suggestions

* fixing unit test

* fixing linting

* fall back to local

* fix linting

* updating based on slack feedback
2023-04-06 14:19:51 -05:00
Nishant Das
aad7aa79d4 Fix Next State Mismatch (#12247)
* fix mismatch

* add regression test
2023-04-06 17:52:15 +08:00
terencechain
2eb2f87913 Default to local payload should set block to not blind (#12243) 2023-04-05 23:29:41 +00:00
Patrice Vignola
9214364c5e Add REST API endpoint for beacon chain client's ListValidators (#12228)
Co-authored-by: Radosław Kapka <rkapka@wp.pl>
2023-04-05 13:00:49 +02:00
Potuz
fb65421678 refactor next slot cache (#12233)
* refactor next slot cache

* fix test

* rename function

* fix spectests

* remove TODO comments

---------

Co-authored-by: Nishant Das <nishdas93@gmail.com>
2023-04-04 16:04:00 +00:00
terencechain
35e3eeddf9 Add flag to boost local block value (#12227)
* Add builder bid fraction to compare with local block value and use builder bid if (bid * fraction) > local block value

* Prioritize local block construction over relay/builder block construction using a boost value for local block construction

* Refactor builder and local block value calculation to use percentage comparison

* Add a test for local with boost

* Use uint64

* Fix log
2023-04-04 14:58:56 +00:00
Sammy Rosso
2618a114e5 Testnet: override Eth1Data for genesisState from input JSON (#12231)
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2023-04-03 15:13:51 +00:00
Radosław Kapka
aac47640b4 Fix broadcast of slashings (#12230)
* Fix broadcast of slashings

* tests
2023-04-03 14:57:59 +00:00
Nishant Das
17cfc60bdd Enable Static Peer ID (#12220)
* static peer id

* kasey's review
2023-04-01 00:00:11 +00:00
Radosław Kapka
8d001d49d4 Unskip block tests (#12222) 2023-03-31 15:45:42 +00:00
Nishant Das
5ecebbe15a Recover State Summary Correctly (#12214)
* fix it

* add zerohash checks

* preston's review
2023-03-30 09:09:36 -05:00
james-prysm
5ae7e17ada E2E: improve beacon api logging (#12211) 2023-03-30 02:51:04 +00:00
terencechain
17488028a6 Use justified hash as safe block hash when passing attribute (#12196)
* With attribute, use justified hash as safe block hash

* Use UnrealizedJustifiedPayloadBlockHash

* Cleanups

* Add test to forkchoice

* Block proposal

* Fix mock

* Fix test

* Fix rest of the tests

* Potuz feedback

* Fix test

* Use unrealized justified hash for regular fcu
2023-03-29 23:38:36 +00:00
james-prysm
163f65f8a3 E2E: updating web3signer dependency (#12207)
* updating dependency

* missed updating a number
2023-03-29 20:32:34 +00:00
Potuz
6ebe5ea8b2 Faster and cached square root (#12191)
* Faster and cached square root

* deal with 0

* Rename function

---------

Co-authored-by: terencechain <terence@prysmaticlabs.com>
2023-03-29 16:23:16 -03:00
Radosław Kapka
5ea0417df2 Improve voluntary exit confirmation prompt (#12205) 2023-03-29 14:17:21 +00:00
Patrice Vignola
61fed336e1 Add REST API endpoint for node client's GetSyncStatus (#12189)
Co-authored-by: james-prysm <90280386+james-prysm@users.noreply.github.com>
2023-03-29 13:38:31 +00:00
Nishant Das
fed6a351cc Update Dependencies (#12204)
* update

* update
2023-03-29 13:04:47 +00:00
Radosław Kapka
98949d8075 Block rewards API endpoint (#12020)
Co-authored-by: terencechain <terence@prysmaticlabs.com>
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2023-03-28 18:44:41 +02:00
Nishant Das
5cbbd26df4 Fallback in Update Head On Error (#12199)
* return if head call fails

* potuz's feedback

* potuz's feedback
2023-03-28 23:06:44 +08:00
Patrice Vignola
83ccb15e66 Add REST API endpoint for node client's GetGenesis (#12168)
* Add REST API endpoint for node client's GetGenesis

* Remove unused parameter

* Fix test name

---------

Co-authored-by: Radosław Kapka <rkapka@wp.pl>
2023-03-28 11:36:41 +00:00
james-prysm
f5bfb8e9eb revert protobuf depreciation - ValidatorPerformanceResponse (#12192)
* accidently deprecated protobuf message

* accidently checked in blob changes
2023-03-27 13:39:21 -05:00
terencechain
b00f7f4592 Update the badges to latest version (#12145)
Co-authored-by: james-prysm <90280386+james-prysm@users.noreply.github.com>
Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>
2023-03-24 18:02:53 +00:00
Nishant Das
191e603e28 Fix Bad Merge in V4 (#12183) 2023-03-24 14:05:31 +00:00
Nishant Das
76c729f9fa Add Pubsub Metrics Tracer (#12178)
* add tracer

* gaz

* preston's review

* preston's review
2023-03-24 12:36:10 +08:00
Potuz
797cc360c7 Isolate forkchoice to blockchain package (#12174)
* Isolate Forkchoice to blockchain package

* Nishant's feedback

* Terence's feedback

* Nishant saving the day
2023-03-22 09:12:54 +08:00
terencechain
79da486508 Add locks to forkchoice spec tests (#12165)
* Add locks to forkchoice spec testS

* Fix

* Rm forkchoice store getter

* Rm useless lock
2023-03-21 18:39:40 +00:00
terencechain
5bb1491d8f Remove blob protos (#12173)
* Remove old protobufs

* Rm generated files

---------

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2023-03-21 18:08:05 +00:00
Patrice Vignola
c0ee781638 Remove unused validator endpoints from validator REST API (#12167)
Co-authored-by: Radosław Kapka <rkapka@wp.pl>
2023-03-21 16:52:42 +00:00
shana
4d5827c527 Fix payload attributes json (#12169)
Co-authored-by: terencechain <terence@prysmaticlabs.com>
2023-03-21 13:36:18 +00:00
Nishant Das
88f03967dd Apply Goimports to Generated Files (#12170)
* gofmt

* build
2023-03-21 11:12:23 +00:00
Potuz
fb65287ba2 Remove unused methods from interface (#12164) 2023-03-20 15:36:33 -05:00
Radosław Kapka
0cb46eb29a Do not HTR the state when checking for optimistic mode (#12143)
* initial impl

* review feedback

* fix tests

* review feedback

* some improvements

* tests and small improvements

* gzl

* one more review

* fix test

* fix other test

* get the roots instead of hashing them

* fix comment

* fix justified case

* fix all tests

* misc

* gzl

* fix broken tests

* use isOptimisticForRoot once we have the blockroot

* Fix is_not_finalized_when_head_is_optimistic but reviewing the logic first

* Fix is_not_finalized_when_head_is_optimistic

* better root tests

* move optimistic check before parsing root

* check for last validated checkpoint

* add right check for finalized

* fix finalized tests

* removed impossible condition

* fix TestGetSyncCommitteeDuties

* Use Ancestor from chaininfo

* fix test

---------

Co-authored-by: Potuz <potuz@prysmaticlabs.com>
Co-authored-by: Nishant Das <nishdas93@gmail.com>
Co-authored-by: rauljordan <raul@prysmaticlabs.com>
Co-authored-by: terence tsao <terence@prysmaticlabs.com>
2023-03-20 17:04:40 -03:00
Potuz
abe9e7fa7e mainnet capella epoch (#12144)
* mainnet capella epoch

* Update spec test to v1.3.0-rc5

---------

Co-authored-by: terence tsao <terence@prysmaticlabs.com>
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2023-03-20 19:18:58 +00:00
Potuz
3536669a70 lock forkchoice on calls to Ancestor (#12162)
Co-authored-by: terencechain <terence@prysmaticlabs.com>
2023-03-20 15:51:42 -03:00
Patrice Vignola
7c49277e83 Add REST API stubs for beacon chain, node and slasher clients (#12094)
* WIP

* WIP

* Remove duplicate mock

* WIP

* Revert "WIP"

This reverts commit a8010057fe.

* Fix build break

* Remove unused variable

* Fix build break

* Rename validator_mock to validatormock

* Fix failing test

---------

Co-authored-by: james-prysm <90280386+james-prysm@users.noreply.github.com>
Co-authored-by: Radosław Kapka <rkapka@wp.pl>
2023-03-20 16:32:32 +00:00
terencechain
6480d5a0fd Send missing slot event at the correct place (#12160) 2023-03-19 16:25:58 -07:00
Potuz
d1c45b44be Call FCU at 4 seconds if we haven't updated head (#12159) 2023-03-19 00:21:52 +00:00
319 changed files with 8918 additions and 5679 deletions

View File

@@ -17,6 +17,7 @@ linters:
- errcheck
- gosimple
- gocognit
- misspell
linters-settings:
gocognit:

View File

@@ -2,8 +2,8 @@
[![Build status](https://badge.buildkite.com/b555891daf3614bae4284dcf365b2340cefc0089839526f096.svg?branch=master)](https://buildkite.com/prysmatic-labs/prysm)
[![Go Report Card](https://goreportcard.com/badge/github.com/prysmaticlabs/prysm)](https://goreportcard.com/report/github.com/prysmaticlabs/prysm)
[![Consensus_Spec_Version 1.2.0](https://img.shields.io/badge/Consensus%20Spec%20Version-v1.2.0-blue.svg)](https://github.com/ethereum/consensus-specs/tree/v1.2.0)
[![Execution_API_Version 1.0.0-beta.1](https://img.shields.io/badge/Execution%20API%20Version-v1.0.0.beta.1-blue.svg)](https://github.com/ethereum/execution-apis/tree/v1.0.0-beta.1/src/engine)
[![Consensus_Spec_Version 1.3.0](https://img.shields.io/badge/Consensus%20Spec%20Version-v1.3.0-blue.svg)](https://github.com/ethereum/consensus-specs/tree/v1.3.0)
[![Execution_API_Version 1.0.0-beta.2](https://img.shields.io/badge/Execution%20API%20Version-v1.0.0.beta.2-blue.svg)](https://github.com/ethereum/execution-apis/tree/v1.0.0-beta.2/src/engine)
[![Discord](https://user-images.githubusercontent.com/7288322/34471967-1df7808a-efbb-11e7-9088-ed0b04151291.png)](https://discord.gg/CTYGPUJ)
[![GitPOAP Badge](https://public-api.gitpoap.io/v1/repo/prysmaticlabs/prysm/badge)](https://www.gitpoap.io/gh/prysmaticlabs/prysm)

View File

@@ -164,7 +164,7 @@ load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_depe
go_rules_dependencies()
go_register_toolchains(
go_version = "1.19.7",
go_version = "1.19.8",
nogo = "@//:nogo",
)
@@ -205,7 +205,7 @@ filegroup(
url = "https://github.com/ethereum/EIPs/archive/5480440fe51742ed23342b68cf106cefd427e39d.tar.gz",
)
consensus_spec_version = "v1.3.0-rc.4"
consensus_spec_version = "v1.3.0-rc.5"
bls_test_version = "v0.1.1"
@@ -221,7 +221,7 @@ filegroup(
visibility = ["//visibility:public"],
)
""",
sha256 = "519da3cbb181fe927e41b0d13c3aaad5f5f38fe0ba87ca51bd09a661c738bd6c",
sha256 = "266006512e71e62396e8f31be01639560c9d59a93c38220fd8f51fabefc8f5f3",
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/general.tar.gz" % consensus_spec_version,
)
@@ -237,7 +237,7 @@ filegroup(
visibility = ["//visibility:public"],
)
""",
sha256 = "894404302d3d4b0f3080d3221204c19de4e837f1b129f468a66747103174412e",
sha256 = "2ebf483830165909cb7961562fd369dedf079997a4832cc215a543898a73aa46",
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/minimal.tar.gz" % consensus_spec_version,
)
@@ -253,7 +253,7 @@ filegroup(
visibility = ["//visibility:public"],
)
""",
sha256 = "ca7a594a2f4be1103e01b5a1416f75a328b7555eae8b26308c07f80fa6d0f255",
sha256 = "333718ba5c907e0a99580caa8d28dd710543b3b271e4251581006d0e101fbce9",
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/mainnet.tar.gz" % consensus_spec_version,
)
@@ -268,7 +268,7 @@ filegroup(
visibility = ["//visibility:public"],
)
""",
sha256 = "b4ed6c077c5f0857361412515b319fc8b26730c7d701d3245b5e6849b3974a4f",
sha256 = "78b6925b5a4208e32385fa4387d2c27b381a8ddd18d66d5a7787e7846b86bfc8",
strip_prefix = "consensus-specs-" + consensus_spec_version[1:],
url = "https://github.com/ethereum/consensus-specs/archive/refs/tags/%s.tar.gz" % consensus_spec_version,
)

View File

@@ -157,6 +157,7 @@ func (c *Client) do(ctx context.Context, method string, path string, body io.Rea
if err != nil {
return
}
req.Header.Add("User-Agent", version.BuildData())
for _, o := range opts {
o(req)
}

View File

@@ -70,15 +70,16 @@ type Gateway struct {
func New(ctx context.Context, opts ...Option) (*Gateway, error) {
g := &Gateway{
ctx: ctx,
cfg: &config{
router: mux.NewRouter(),
},
cfg: &config{},
}
for _, opt := range opts {
if err := opt(g); err != nil {
return nil, err
}
}
if g.cfg.router == nil {
g.cfg.router = mux.NewRouter()
}
return g, nil
}

View File

@@ -10,11 +10,6 @@ import (
type Option func(g *Gateway) error
func (g *Gateway) SetRouter(r *mux.Router) *Gateway {
g.cfg.router = r
return g
}
func WithPbHandlers(handlers []*PbMux) Option {
return func(g *Gateway) error {
g.cfg.pbHandlers = handlers

View File

@@ -4,6 +4,7 @@ go_library(
name = "go_default_library",
srcs = [
"chain_info.go",
"chain_info_forkchoice.go",
"error.go",
"execution_engine.go",
"forkchoice_update_execution.go",

View File

@@ -7,7 +7,6 @@ import (
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice"
doublylinkedtree "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/doubly-linked-tree"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
@@ -15,6 +14,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
ethpbv1 "github.com/prysmaticlabs/prysm/v4/proto/eth/v1"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v4/time/slots"
"go.opencensus.io/trace"
@@ -28,12 +28,25 @@ type ChainInfoFetcher interface {
CanonicalFetcher
ForkFetcher
HeadDomainFetcher
ForkchoiceFetcher
}
// HeadUpdater defines a common interface for methods in blockchain service
// which allow to update the head info
type HeadUpdater interface {
// ForkchoiceFetcher defines a common interface for methods that access directly
// forkchoice information. These typically require a lock and external callers
// are requested to call methods within this blockchain package that takes care
// of locking forkchoice
type ForkchoiceFetcher interface {
Ancestor(context.Context, []byte, primitives.Slot) ([]byte, error)
CachedHeadRoot() [32]byte
GetProposerHead() [32]byte
SetForkChoiceGenesisTime(uint64)
UpdateHead(context.Context, primitives.Slot)
HighestReceivedBlockSlot() primitives.Slot
ReceivedBlocksLastEpoch() (uint64, error)
InsertNode(context.Context, state.BeaconState, [32]byte) error
ForkChoiceDump(context.Context) (*ethpbv1.ForkChoiceDump, error)
NewSlot(context.Context, primitives.Slot) error
ProposerBoost() [32]byte
}
// TimeFetcher retrieves the Ethereum consensus data that's related to time.
@@ -67,7 +80,6 @@ type HeadFetcher interface {
// ForkFetcher retrieves the current fork information of the Ethereum beacon chain.
type ForkFetcher interface {
ForkChoicer() forkchoice.ForkChoicer
CurrentFork() *ethpb.Fork
GenesisFetcher
TimeFetcher
@@ -84,6 +96,8 @@ type FinalizationFetcher interface {
FinalizedCheckpt() *ethpb.Checkpoint
CurrentJustifiedCheckpt() *ethpb.Checkpoint
PreviousJustifiedCheckpt() *ethpb.Checkpoint
UnrealizedJustifiedPayloadBlockHash() ([32]byte, error)
FinalizedBlockHash() [32]byte
InForkchoice([32]byte) bool
IsFinalized(ctx context.Context, blockRoot [32]byte) bool
}
@@ -96,25 +110,25 @@ type OptimisticModeFetcher interface {
// FinalizedCheckpt returns the latest finalized checkpoint from chain store.
func (s *Service) FinalizedCheckpt() *ethpb.Checkpoint {
s.ForkChoicer().RLock()
defer s.ForkChoicer().RUnlock()
cp := s.ForkChoicer().FinalizedCheckpoint()
s.cfg.ForkChoiceStore.RLock()
defer s.cfg.ForkChoiceStore.RUnlock()
cp := s.cfg.ForkChoiceStore.FinalizedCheckpoint()
return &ethpb.Checkpoint{Epoch: cp.Epoch, Root: bytesutil.SafeCopyBytes(cp.Root[:])}
}
// PreviousJustifiedCheckpt returns the current justified checkpoint from chain store.
func (s *Service) PreviousJustifiedCheckpt() *ethpb.Checkpoint {
s.ForkChoicer().RLock()
defer s.ForkChoicer().RUnlock()
cp := s.ForkChoicer().PreviousJustifiedCheckpoint()
s.cfg.ForkChoiceStore.RLock()
defer s.cfg.ForkChoiceStore.RUnlock()
cp := s.cfg.ForkChoiceStore.PreviousJustifiedCheckpoint()
return &ethpb.Checkpoint{Epoch: cp.Epoch, Root: bytesutil.SafeCopyBytes(cp.Root[:])}
}
// CurrentJustifiedCheckpt returns the current justified checkpoint from chain store.
func (s *Service) CurrentJustifiedCheckpt() *ethpb.Checkpoint {
s.ForkChoicer().RLock()
defer s.ForkChoicer().RUnlock()
cp := s.ForkChoicer().JustifiedCheckpoint()
s.cfg.ForkChoiceStore.RLock()
defer s.cfg.ForkChoiceStore.RUnlock()
cp := s.cfg.ForkChoiceStore.JustifiedCheckpoint()
return &ethpb.Checkpoint{Epoch: cp.Epoch, Root: bytesutil.SafeCopyBytes(cp.Root[:])}
}
@@ -277,8 +291,8 @@ func (s *Service) CurrentFork() *ethpb.Fork {
// IsCanonical returns true if the input block root is part of the canonical chain.
func (s *Service) IsCanonical(ctx context.Context, blockRoot [32]byte) (bool, error) {
s.ForkChoicer().RLock()
defer s.ForkChoicer().RUnlock()
s.cfg.ForkChoiceStore.RLock()
defer s.cfg.ForkChoiceStore.RUnlock()
// If the block has not been finalized, check fork choice store to see if the block is canonical
if s.cfg.ForkChoiceStore.HasNode(blockRoot) {
return s.cfg.ForkChoiceStore.IsCanonical(blockRoot), nil
@@ -288,14 +302,6 @@ func (s *Service) IsCanonical(ctx context.Context, blockRoot [32]byte) (bool, er
return s.cfg.BeaconDB.IsFinalizedBlock(ctx, blockRoot), nil
}
// ChainHeads returns all possible chain heads (leaves of fork choice tree).
// Heads roots and heads slots are returned.
func (s *Service) ChainHeads() ([][32]byte, []primitives.Slot) {
s.ForkChoicer().RLock()
defer s.ForkChoicer().RUnlock()
return s.cfg.ForkChoiceStore.Tips()
}
// HeadPublicKeyToValidatorIndex returns the validator index of the `pubkey` in current head state.
func (s *Service) HeadPublicKeyToValidatorIndex(pubKey [fieldparams.BLSPubkeyLength]byte) (primitives.ValidatorIndex, bool) {
s.headLock.RLock()
@@ -320,11 +326,6 @@ func (s *Service) HeadValidatorIndexToPublicKey(_ context.Context, index primiti
return v.PublicKey(), nil
}
// ForkChoicer returns the forkchoice interface.
func (s *Service) ForkChoicer() forkchoice.ForkChoicer {
return s.cfg.ForkChoiceStore
}
// IsOptimistic returns true if the current head is optimistic.
func (s *Service) IsOptimistic(ctx context.Context) (bool, error) {
if slots.ToEpoch(s.CurrentSlot()) < params.BeaconConfig().BellatrixForkEpoch {
@@ -334,8 +335,8 @@ func (s *Service) IsOptimistic(ctx context.Context) (bool, error) {
headRoot := s.head.root
s.headLock.RUnlock()
s.ForkChoicer().RLock()
defer s.ForkChoicer().RUnlock()
s.cfg.ForkChoiceStore.RLock()
defer s.cfg.ForkChoiceStore.RUnlock()
optimistic, err := s.cfg.ForkChoiceStore.IsOptimistic(headRoot)
if err == nil {
return optimistic, nil
@@ -351,14 +352,14 @@ func (s *Service) IsOptimistic(ctx context.Context) (bool, error) {
// IsFinalized returns true if the input root is finalized.
// It first checks latest finalized root then checks finalized root index in DB.
func (s *Service) IsFinalized(ctx context.Context, root [32]byte) bool {
s.ForkChoicer().RLock()
defer s.ForkChoicer().RUnlock()
if s.ForkChoicer().FinalizedCheckpoint().Root == root {
s.cfg.ForkChoiceStore.RLock()
defer s.cfg.ForkChoiceStore.RUnlock()
if s.cfg.ForkChoiceStore.FinalizedCheckpoint().Root == root {
return true
}
// If node exists in our store, then it is not
// finalized.
if s.ForkChoicer().HasNode(root) {
if s.cfg.ForkChoiceStore.HasNode(root) {
return false
}
return s.cfg.BeaconDB.IsFinalizedBlock(ctx, root)
@@ -368,17 +369,17 @@ func (s *Service) IsFinalized(ctx context.Context, root [32]byte) bool {
// This in particular means that the blockroot is a descendant of the
// finalized checkpoint
func (s *Service) InForkchoice(root [32]byte) bool {
s.ForkChoicer().RLock()
defer s.ForkChoicer().RUnlock()
return s.ForkChoicer().HasNode(root)
s.cfg.ForkChoiceStore.RLock()
defer s.cfg.ForkChoiceStore.RUnlock()
return s.cfg.ForkChoiceStore.HasNode(root)
}
// IsOptimisticForRoot takes the root as argument instead of the current head
// and returns true if it is optimistic.
func (s *Service) IsOptimisticForRoot(ctx context.Context, root [32]byte) (bool, error) {
s.ForkChoicer().RLock()
s.cfg.ForkChoiceStore.RLock()
optimistic, err := s.cfg.ForkChoiceStore.IsOptimistic(root)
s.ForkChoicer().RUnlock()
s.cfg.ForkChoiceStore.RUnlock()
if err == nil {
return optimistic, nil
}
@@ -401,7 +402,10 @@ func (s *Service) IsOptimisticForRoot(ctx context.Context, root [32]byte) (bool,
}
if ss == nil {
return true, errInvalidNilSummary
ss, err = s.recoverStateSummary(ctx, root)
if err != nil {
return true, err
}
}
validatedCheckpoint, err := s.cfg.BeaconDB.LastValidatedCheckpoint(ctx)
if err != nil {
@@ -427,7 +431,10 @@ func (s *Service) IsOptimisticForRoot(ctx context.Context, root [32]byte) (bool,
return false, err
}
if lastValidated == nil {
return false, errInvalidNilSummary
lastValidated, err = s.recoverStateSummary(ctx, root)
if err != nil {
return false, err
}
}
if ss.Slot > lastValidated.Slot {
@@ -436,12 +443,57 @@ func (s *Service) IsOptimisticForRoot(ctx context.Context, root [32]byte) (bool,
return !isCanonical, nil
}
// Ancestor returns the block root of an ancestry block from the input block root.
//
// Spec pseudocode definition:
//
// def get_ancestor(store: Store, root: Root, slot: Slot) -> Root:
// block = store.blocks[root]
// if block.slot > slot:
// return get_ancestor(store, block.parent_root, slot)
// elif block.slot == slot:
// return root
// else:
// # root is older than queried slot, thus a skip slot. Return most recent root prior to slot
// return root
func (s *Service) Ancestor(ctx context.Context, root []byte, slot primitives.Slot) ([]byte, error) {
ctx, span := trace.StartSpan(ctx, "blockChain.ancestor")
defer span.End()
r := bytesutil.ToBytes32(root)
// Get ancestor root from fork choice store instead of recursively looking up blocks in DB.
// This is most optimal outcome.
s.cfg.ForkChoiceStore.RLock()
ar, err := s.cfg.ForkChoiceStore.AncestorRoot(ctx, r, slot)
s.cfg.ForkChoiceStore.RUnlock()
if err != nil {
// Try getting ancestor root from DB when failed to retrieve from fork choice store.
// This is the second line of defense for retrieving ancestor root.
ar, err = s.ancestorByDB(ctx, r, slot)
if err != nil {
return nil, err
}
}
return ar[:], nil
}
// SetGenesisTime sets the genesis time of beacon chain.
func (s *Service) SetGenesisTime(t time.Time) {
s.genesisTime = t
}
// ForkChoiceStore returns the fork choice store in the service.
func (s *Service) ForkChoiceStore() forkchoice.ForkChoicer {
return s.cfg.ForkChoiceStore
func (s *Service) recoverStateSummary(ctx context.Context, blockRoot [32]byte) (*ethpb.StateSummary, error) {
if s.cfg.BeaconDB.HasBlock(ctx, blockRoot) {
b, err := s.cfg.BeaconDB.Block(ctx, blockRoot)
if err != nil {
return nil, err
}
summary := &ethpb.StateSummary{Slot: b.Block().Slot(), Root: blockRoot[:]}
if err := s.cfg.BeaconDB.SaveStateSummary(ctx, summary); err != nil {
return nil, err
}
return summary, nil
}
return nil, errBlockDoesNotExist
}

View File

@@ -0,0 +1,94 @@
package blockchain
import (
"context"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
ethpbv1 "github.com/prysmaticlabs/prysm/v4/proto/eth/v1"
)
// CachedHeadRoot returns the corresponding value from Forkchoice
func (s *Service) CachedHeadRoot() [32]byte {
s.cfg.ForkChoiceStore.RLock()
defer s.cfg.ForkChoiceStore.RUnlock()
return s.cfg.ForkChoiceStore.CachedHeadRoot()
}
// GetProposerHead returns the corresponding value from forkchoice
func (s *Service) GetProposerHead() [32]byte {
s.cfg.ForkChoiceStore.RLock()
defer s.cfg.ForkChoiceStore.RUnlock()
return s.cfg.ForkChoiceStore.GetProposerHead()
}
// SetForkChoiceGenesisTime sets the genesis time in Forkchoice
func (s *Service) SetForkChoiceGenesisTime(timestamp uint64) {
s.cfg.ForkChoiceStore.Lock()
defer s.cfg.ForkChoiceStore.Unlock()
s.cfg.ForkChoiceStore.SetGenesisTime(timestamp)
}
// HighestReceivedBlockSlot returns the corresponding value from forkchoice
func (s *Service) HighestReceivedBlockSlot() primitives.Slot {
s.cfg.ForkChoiceStore.RLock()
defer s.cfg.ForkChoiceStore.RUnlock()
return s.cfg.ForkChoiceStore.HighestReceivedBlockSlot()
}
// ReceivedBlocksLastEpoch returns the corresponding value from forkchoice
func (s *Service) ReceivedBlocksLastEpoch() (uint64, error) {
s.cfg.ForkChoiceStore.RLock()
defer s.cfg.ForkChoiceStore.RUnlock()
return s.cfg.ForkChoiceStore.ReceivedBlocksLastEpoch()
}
// InsertNode is a wrapper for node insertion which is self locked
func (s *Service) InsertNode(ctx context.Context, st state.BeaconState, root [32]byte) error {
s.cfg.ForkChoiceStore.Lock()
defer s.cfg.ForkChoiceStore.Unlock()
return s.cfg.ForkChoiceStore.InsertNode(ctx, st, root)
}
// ForkChoiceDump returns the corresponding value from forkchoice
func (s *Service) ForkChoiceDump(ctx context.Context) (*ethpbv1.ForkChoiceDump, error) {
s.cfg.ForkChoiceStore.RLock()
defer s.cfg.ForkChoiceStore.RUnlock()
return s.cfg.ForkChoiceStore.ForkChoiceDump(ctx)
}
// NewSlot returns the corresponding value from forkchoice
func (s *Service) NewSlot(ctx context.Context, slot primitives.Slot) error {
s.cfg.ForkChoiceStore.Lock()
defer s.cfg.ForkChoiceStore.Unlock()
return s.cfg.ForkChoiceStore.NewSlot(ctx, slot)
}
// ProposerBoost wraps the corresponding method from forkchoice
func (s *Service) ProposerBoost() [32]byte {
s.cfg.ForkChoiceStore.Lock()
defer s.cfg.ForkChoiceStore.Unlock()
return s.cfg.ForkChoiceStore.ProposerBoost()
}
// ChainHeads returns all possible chain heads (leaves of fork choice tree).
// Heads roots and heads slots are returned.
func (s *Service) ChainHeads() ([][32]byte, []primitives.Slot) {
s.cfg.ForkChoiceStore.RLock()
defer s.cfg.ForkChoiceStore.RUnlock()
return s.cfg.ForkChoiceStore.Tips()
}
// UnrealizedJustifiedPayloadBlockHash returns unrealized justified payload block hash from forkchoice.
func (s *Service) UnrealizedJustifiedPayloadBlockHash() ([32]byte, error) {
s.cfg.ForkChoiceStore.RLock()
defer s.cfg.ForkChoiceStore.RUnlock()
return s.cfg.ForkChoiceStore.UnrealizedJustifiedPayloadBlockHash()
}
// FinalizedBlockHash returns finalized payload block hash from forkchoice.
func (s *Service) FinalizedBlockHash() [32]byte {
s.cfg.ForkChoiceStore.RLock()
defer s.cfg.ForkChoiceStore.RUnlock()
return s.cfg.ForkChoiceStore.FinalizedPayloadBlockHash()
}

View File

@@ -71,12 +71,6 @@ func TestHeadRoot_Nil(t *testing.T) {
assert.DeepEqual(t, params.BeaconConfig().ZeroHash[:], headRoot, "Incorrect pre chain start value")
}
func TestService_ForkChoiceStore(t *testing.T) {
c := &Service{cfg: &config{ForkChoiceStore: doublylinkedtree.New()}}
p := c.ForkChoiceStore()
require.Equal(t, primitives.Epoch(0), p.FinalizedCheckpoint().Epoch)
}
func TestFinalizedCheckpt_GenesisRootOk(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
@@ -125,6 +119,46 @@ func TestCurrentJustifiedCheckpt_CanRetrieve(t *testing.T) {
require.Equal(t, cp.Root, bytesutil.ToBytes32(jp.Root))
}
func TestFinalizedBlockHash(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithForkChoiceStore(fcs),
WithStateGen(stategen.New(beaconDB, fcs)),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
r := [32]byte{'f'}
cp := &forkchoicetypes.Checkpoint{Epoch: 6, Root: r}
bState, _ := util.DeterministicGenesisState(t, 10)
require.NoError(t, beaconDB.SaveState(ctx, bState, r))
require.NoError(t, fcs.UpdateFinalizedCheckpoint(cp))
h := service.FinalizedBlockHash()
require.Equal(t, params.BeaconConfig().ZeroHash, h)
require.Equal(t, r, fcs.FinalizedCheckpoint().Root)
}
func TestUnrealizedJustifiedBlockHash(t *testing.T) {
ctx := context.Background()
service := &Service{cfg: &config{ForkChoiceStore: doublylinkedtree.New()}}
ojc := &ethpb.Checkpoint{Root: []byte{'j'}}
ofc := &ethpb.Checkpoint{Root: []byte{'f'}}
st, blkRoot, err := prepareForkchoiceState(ctx, 0, [32]byte{}, [32]byte{}, params.BeaconConfig().ZeroHash, ojc, ofc)
require.NoError(t, err)
require.NoError(t, service.cfg.ForkChoiceStore.InsertNode(ctx, st, blkRoot))
service.cfg.ForkChoiceStore.SetBalancesByRooter(func(_ context.Context, _ [32]byte) ([]uint64, error) { return []uint64{}, nil })
require.NoError(t, service.cfg.ForkChoiceStore.UpdateJustifiedCheckpoint(ctx, &forkchoicetypes.Checkpoint{Epoch: 6, Root: [32]byte{'j'}}))
h, err := service.UnrealizedJustifiedPayloadBlockHash()
require.NoError(t, err)
require.Equal(t, params.BeaconConfig().ZeroHash, h)
require.Equal(t, [32]byte{'j'}, service.cfg.ForkChoiceStore.JustifiedCheckpoint().Root)
}
func TestHeadSlot_CanRetrieve(t *testing.T) {
c := &Service{}
s, err := state_native.InitializeFromProtoPhase0(&ethpb.BeaconState{})
@@ -484,15 +518,10 @@ func TestService_IsOptimisticForRoot_DB(t *testing.T) {
validatedCheckpoint := &ethpb.Checkpoint{Root: br[:]}
require.NoError(t, beaconDB.SaveLastValidatedCheckpoint(ctx, validatedCheckpoint))
_, err = c.IsOptimisticForRoot(ctx, optimisticRoot)
require.ErrorContains(t, "nil summary returned from the DB", err)
require.NoError(t, beaconDB.SaveStateSummary(context.Background(), &ethpb.StateSummary{Root: optimisticRoot[:], Slot: 11}))
optimistic, err := c.IsOptimisticForRoot(ctx, optimisticRoot)
require.NoError(t, err)
require.Equal(t, true, optimistic)
require.NoError(t, beaconDB.SaveStateSummary(context.Background(), &ethpb.StateSummary{Root: validatedRoot[:], Slot: 9}))
cp := &ethpb.Checkpoint{
Epoch: 1,
Root: validatedRoot[:],
@@ -554,12 +583,31 @@ func TestService_IsOptimisticForRoot_DB_non_canonical(t *testing.T) {
}
func TestService_IsOptimisticForRoot_StateSummaryRecovered(t *testing.T) {
beaconDB := testDB.SetupDB(t)
ctx := context.Background()
c := &Service{cfg: &config{BeaconDB: beaconDB, ForkChoiceStore: doublylinkedtree.New()}, head: &head{root: [32]byte{'b'}}}
c.head = &head{root: params.BeaconConfig().ZeroHash}
b := util.NewBeaconBlock()
b.Block.Slot = 10
br, err := b.Block.HashTreeRoot()
require.NoError(t, err)
util.SaveBlock(t, context.Background(), beaconDB, b)
_, err = c.IsOptimisticForRoot(ctx, br)
assert.NoError(t, err)
summ, err := beaconDB.StateSummary(ctx, br)
assert.NoError(t, err)
assert.NotNil(t, summ)
assert.Equal(t, 10, int(summ.Slot))
assert.DeepEqual(t, br[:], summ.Root)
}
func TestService_IsFinalized(t *testing.T) {
beaconDB := testDB.SetupDB(t)
ctx := context.Background()
c := &Service{cfg: &config{BeaconDB: beaconDB, ForkChoiceStore: doublylinkedtree.New()}}
r1 := [32]byte{'a'}
require.NoError(t, c.ForkChoiceStore().UpdateFinalizedCheckpoint(&forkchoicetypes.Checkpoint{
require.NoError(t, c.cfg.ForkChoiceStore.UpdateFinalizedCheckpoint(&forkchoicetypes.Checkpoint{
Root: r1,
}))
b := util.NewBeaconBlock()

View File

@@ -15,8 +15,8 @@ var (
errNilFinalizedCheckpoint = errors.New("nil finalized checkpoint returned from state")
// errNilJustifiedCheckpoint is returned when a nil justified checkpt is returned from a state.
errNilJustifiedCheckpoint = errors.New("nil justified checkpoint returned from state")
// errInvalidNilSummary is returned when a nil summary is returned from the DB.
errInvalidNilSummary = errors.New("nil summary returned from the DB")
// errBlockDoesNotExist is returned when a block does not exist for a particular state summary.
errBlockDoesNotExist = errors.New("could not find block in DB")
// errWrongBlockCount is returned when the wrong number of blocks or block roots is used
errWrongBlockCount = errors.New("wrong number of blocks or block roots")
// errBlockNotFoundInCacheOrDB is returned when a block is not found in the cache or DB.

View File

@@ -12,6 +12,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/db/kv"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/execution"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
"github.com/prysmaticlabs/prysm/v4/config/features"
"github.com/prysmaticlabs/prysm/v4/config/params"
consensusblocks "github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces"
@@ -60,8 +61,12 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *notifyForkcho
log.WithError(err).Error("Could not get execution payload for head block")
return nil, nil
}
finalizedHash := s.ForkChoicer().FinalizedPayloadBlockHash()
justifiedHash := s.ForkChoicer().JustifiedPayloadBlockHash()
finalizedHash := s.cfg.ForkChoiceStore.FinalizedPayloadBlockHash()
justifiedHash, err := s.cfg.ForkChoiceStore.UnrealizedJustifiedPayloadBlockHash()
if err != nil {
log.WithError(err).Error("Could not get unrealized justified payload block hash")
justifiedHash = finalizedHash
}
fcs := &enginev1.ForkchoiceState{
HeadBlockHash: headPayload.BlockHash(),
SafeBlockHash: justifiedHash[:],
@@ -88,7 +93,7 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *notifyForkcho
if len(lastValidHash) == 0 {
lastValidHash = defaultLatestValidHash
}
invalidRoots, err := s.ForkChoicer().SetOptimisticToInvalid(ctx, headRoot, headBlk.ParentRoot(), bytesutil.ToBytes32(lastValidHash))
invalidRoots, err := s.cfg.ForkChoiceStore.SetOptimisticToInvalid(ctx, headRoot, headBlk.ParentRoot(), bytesutil.ToBytes32(lastValidHash))
if err != nil {
log.WithError(err).Error("Could not set head root to invalid")
return nil, nil
@@ -224,7 +229,7 @@ func (s *Service) notifyNewPayload(ctx context.Context, postStateVersion int,
if err != nil {
return false, err
}
invalidRoots, err := s.ForkChoicer().SetOptimisticToInvalid(ctx, root, blk.Block().ParentRoot(), bytesutil.ToBytes32(lastValidHash))
invalidRoots, err := s.cfg.ForkChoiceStore.SetOptimisticToInvalid(ctx, root, blk.Block().ParentRoot(), bytesutil.ToBytes32(lastValidHash))
if err != nil {
return false, err
}
@@ -254,7 +259,7 @@ func (s *Service) getPayloadAttribute(ctx context.Context, st state.BeaconState,
emptyAttri := payloadattribute.EmptyWithVersion(st.Version())
// Root is `[32]byte{}` since we are retrieving proposer ID of a given slot. During insertion at assignment the root was not known.
proposerID, _, ok := s.cfg.ProposerSlotIndexCache.GetProposerPayloadIDs(slot, [32]byte{} /* root */)
if !ok { // There's no need to build attribute if there is no proposer for slot.
if !ok && !features.Get().PrepareAllPayloads { // There's no need to build attribute if there is no proposer for slot.
return false, emptyAttri, 0
}

View File

@@ -17,6 +17,7 @@ import (
bstate "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/stategen"
"github.com/prysmaticlabs/prysm/v4/config/features"
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
"github.com/prysmaticlabs/prysm/v4/config/params"
consensusblocks "github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
@@ -824,6 +825,31 @@ func Test_GetPayloadAttribute(t *testing.T) {
require.Equal(t, suggestedAddr, common.BytesToAddress(attr.SuggestedFeeRecipient()))
}
func Test_GetPayloadAttribute_PrepareAllPayloads(t *testing.T) {
ctx := context.Background()
resetCfg := features.InitWithReset(&features.Flags{
PrepareAllPayloads: true,
})
defer resetCfg()
beaconDB := testDB.SetupDB(t)
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, doublylinkedtree.New())),
WithProposerIdsCache(cache.NewProposerPayloadIDsCache()),
}
hook := logTest.NewGlobal()
service, err := NewService(ctx, opts...)
require.NoError(t, err)
st, _ := util.DeterministicGenesisStateBellatrix(t, 1)
hasPayload, attr, vId := service.getPayloadAttribute(ctx, st, 0)
require.Equal(t, true, hasPayload)
require.Equal(t, primitives.ValidatorIndex(0), vId)
require.Equal(t, params.BeaconConfig().EthBurnAddressHex, common.BytesToAddress(attr.SuggestedFeeRecipient()).String())
require.LogsContain(t, hook, "Fee recipient is currently using the burn address")
}
func Test_GetPayloadAttributeV2(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)

View File

@@ -18,7 +18,7 @@ import (
func (s *Service) isNewProposer(slot primitives.Slot) bool {
_, _, ok := s.cfg.ProposerSlotIndexCache.GetProposerPayloadIDs(slot, [32]byte{} /* root */)
return ok
return ok || features.Get().PrepareAllPayloads
}
func (s *Service) isNewHead(r [32]byte) bool {
@@ -89,13 +89,13 @@ func (s *Service) forkchoiceUpdateWithExecution(ctx context.Context, newHeadRoot
// shouldOverrideFCU checks whether the incoming block is still subject to being
// reorged or not by the next proposer.
func (s *Service) shouldOverrideFCU(newHeadRoot [32]byte, proposingSlot primitives.Slot) bool {
headWeight, err := s.ForkChoicer().Weight(newHeadRoot)
headWeight, err := s.cfg.ForkChoiceStore.Weight(newHeadRoot)
if err != nil {
log.WithError(err).WithField("root", fmt.Sprintf("%#x", newHeadRoot)).Warn("could not determine node weight")
}
currentSlot := s.CurrentSlot()
if proposingSlot == currentSlot {
proposerHead := s.ForkChoicer().GetProposerHead()
proposerHead := s.cfg.ForkChoiceStore.GetProposerHead()
if proposerHead != newHeadRoot {
return true
}
@@ -106,7 +106,7 @@ func (s *Service) shouldOverrideFCU(newHeadRoot [32]byte, proposingSlot primitiv
params.BeaconConfig().SecondsPerSlot)
lateBlockFailedAttemptSecondThreshold.Inc()
} else {
if s.ForkChoicer().ShouldOverrideFCU() {
if s.cfg.ForkChoiceStore.ShouldOverrideFCU() {
return true
}
secs, err := slots.SecondsSinceSlotStart(currentSlot,

View File

@@ -28,6 +28,8 @@ import (
// UpdateAndSaveHeadWithBalances updates the beacon state head after getting justified balanced from cache.
// This function is only used in spec-tests, it does save the head after updating it.
func (s *Service) UpdateAndSaveHeadWithBalances(ctx context.Context) error {
s.cfg.ForkChoiceStore.Lock()
defer s.cfg.ForkChoiceStore.Unlock()
headRoot, err := s.cfg.ForkChoiceStore.Head(ctx)
if err != nil {
return errors.Wrap(err, "could not update head")
@@ -52,7 +54,7 @@ type head struct {
// This saves head info to the local service cache, it also saves the
// new head root to the DB.
// Caller of the method MUST aqcuire a lock on forkchoice.
// Caller of the method MUST acquire a lock on forkchoice.
func (s *Service) saveHead(ctx context.Context, newHeadRoot [32]byte, headBlock interfaces.ReadOnlySignedBeaconBlock, headState state.BeaconState) error {
ctx, span := trace.StartSpan(ctx, "blockChain.saveHead")
defer span.End()
@@ -87,25 +89,25 @@ func (s *Service) saveHead(ctx context.Context, newHeadRoot [32]byte, headBlock
newHeadSlot := headBlock.Block().Slot()
newStateRoot := headBlock.Block().StateRoot()
// A chain re-org occurred, so we fire an event notifying the rest of the services.
r, err := s.HeadRoot(ctx)
if err != nil {
return errors.Wrap(err, "could not get old head root")
}
oldHeadRoot := bytesutil.ToBytes32(r)
if headBlock.Block().ParentRoot() != oldHeadRoot {
commonRoot, forkSlot, err := s.ForkChoicer().CommonAncestor(ctx, oldHeadRoot, newHeadRoot)
// A chain re-org occurred, so we fire an event notifying the rest of the services.
commonRoot, forkSlot, err := s.cfg.ForkChoiceStore.CommonAncestor(ctx, oldHeadRoot, newHeadRoot)
if err != nil {
log.WithError(err).Error("Could not find common ancestor root")
commonRoot = params.BeaconConfig().ZeroHash
}
dis := headSlot + newHeadSlot - 2*forkSlot
dep := math.Max(uint64(headSlot-forkSlot), uint64(newHeadSlot-forkSlot))
oldWeight, err := s.ForkChoicer().Weight(oldHeadRoot)
oldWeight, err := s.cfg.ForkChoiceStore.Weight(oldHeadRoot)
if err != nil {
log.WithField("root", fmt.Sprintf("%#x", oldHeadRoot)).Warn("could not determine node weight")
}
newWeight, err := s.ForkChoicer().Weight(newHeadRoot)
newWeight, err := s.cfg.ForkChoiceStore.Weight(newHeadRoot)
if err != nil {
log.WithField("root", fmt.Sprintf("%#x", newHeadRoot)).Warn("could not determine node weight")
}
@@ -123,7 +125,7 @@ func (s *Service) saveHead(ctx context.Context, newHeadRoot [32]byte, headBlock
reorgDistance.Observe(float64(dis))
reorgDepth.Observe(float64(dep))
isOptimistic, err := s.ForkChoicer().IsOptimistic(newHeadRoot)
isOptimistic, err := s.cfg.ForkChoiceStore.IsOptimistic(newHeadRoot)
if err != nil {
return errors.Wrap(err, "could not check if node is optimistically synced")
}
@@ -363,7 +365,7 @@ func (s *Service) notifyNewHeadEvent(
// This saves the Attestations and BLSToExecChanges between `orphanedRoot` and the common ancestor root that is derived using `newHeadRoot`.
// It also filters out the attestations that is one epoch older as a defense so invalid attestations don't flow into the attestation pool.
func (s *Service) saveOrphanedOperations(ctx context.Context, orphanedRoot [32]byte, newHeadRoot [32]byte) error {
commonAncestorRoot, _, err := s.ForkChoicer().CommonAncestor(ctx, newHeadRoot, orphanedRoot)
commonAncestorRoot, _, err := s.cfg.ForkChoiceStore.CommonAncestor(ctx, newHeadRoot, orphanedRoot)
switch {
// Exit early if there's no common ancestor and root doesn't exist, there would be nothing to save.
case errors.Is(err, forkchoice.ErrUnknownCommonAncestor):
@@ -401,6 +403,19 @@ func (s *Service) saveOrphanedOperations(ctx context.Context, orphanedRoot [32]b
}
saveOrphanedAttCount.Inc()
}
for _, as := range orphanedBlk.Block().Body().AttesterSlashings() {
if err := s.cfg.SlashingPool.InsertAttesterSlashing(ctx, s.headStateReadOnly(ctx), as); err != nil {
log.WithError(err).Error("Could not insert reorg attester slashing")
}
}
for _, vs := range orphanedBlk.Block().Body().ProposerSlashings() {
if err := s.cfg.SlashingPool.InsertProposerSlashing(ctx, s.headStateReadOnly(ctx), vs); err != nil {
log.WithError(err).Error("Could not insert reorg proposer slashing")
}
}
for _, v := range orphanedBlk.Block().Body().VoluntaryExits() {
s.cfg.ExitPool.InsertVoluntaryExit(v)
}
if orphanedBlk.Version() >= version.Capella {
changes, err := orphanedBlk.Block().Body().BLSToExecutionChanges()
if err != nil {

View File

@@ -308,7 +308,7 @@ func TestSaveOrphanedAtts(t *testing.T) {
require.NoError(t, err)
state, blkRoot, err := prepareForkchoiceState(ctx, blk.Block.Slot, r, bytesutil.ToBytes32(blk.Block.ParentRoot), [32]byte{}, ojc, ofc)
require.NoError(t, err)
require.NoError(t, service.ForkChoicer().InsertNode(ctx, state, blkRoot))
require.NoError(t, service.cfg.ForkChoiceStore.InsertNode(ctx, state, blkRoot))
util.SaveBlock(t, ctx, beaconDB, blk)
}
@@ -326,6 +326,88 @@ func TestSaveOrphanedAtts(t *testing.T) {
require.DeepEqual(t, wantAtts, atts)
}
func TestSaveOrphanedOps(t *testing.T) {
params.SetupTestConfigCleanup(t)
config := params.BeaconConfig()
config.ShardCommitteePeriod = 0
params.OverrideBeaconConfig(config)
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
service := setupBeaconChain(t, beaconDB)
service.genesisTime = time.Now().Add(time.Duration(-10*int64(1)*int64(params.BeaconConfig().SecondsPerSlot)) * time.Second)
// Chain setup
// 0 -- 1 -- 2 -- 3
// \-4
st, keys := util.DeterministicGenesisState(t, 64)
service.head = &head{state: st}
blkG, err := util.GenerateFullBlock(st, keys, util.DefaultBlockGenConfig(), 0)
assert.NoError(t, err)
util.SaveBlock(t, ctx, service.cfg.BeaconDB, blkG)
rG, err := blkG.Block.HashTreeRoot()
require.NoError(t, err)
blk1, err := util.GenerateFullBlock(st, keys, util.DefaultBlockGenConfig(), 1)
assert.NoError(t, err)
blk1.Block.ParentRoot = rG[:]
r1, err := blk1.Block.HashTreeRoot()
require.NoError(t, err)
blk2, err := util.GenerateFullBlock(st, keys, util.DefaultBlockGenConfig(), 2)
assert.NoError(t, err)
blk2.Block.ParentRoot = r1[:]
r2, err := blk2.Block.HashTreeRoot()
require.NoError(t, err)
blkConfig := util.DefaultBlockGenConfig()
blkConfig.NumBLSChanges = 5
blkConfig.NumProposerSlashings = 1
blkConfig.NumAttesterSlashings = 1
blkConfig.NumVoluntaryExits = 1
blk3, err := util.GenerateFullBlock(st, keys, blkConfig, 3)
assert.NoError(t, err)
blk3.Block.ParentRoot = r2[:]
r3, err := blk3.Block.HashTreeRoot()
require.NoError(t, err)
blk4 := util.NewBeaconBlock()
blk4.Block.Slot = 4
blk4.Block.ParentRoot = rG[:]
r4, err := blk4.Block.HashTreeRoot()
require.NoError(t, err)
ojc := &ethpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
ofc := &ethpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
for _, blk := range []*ethpb.SignedBeaconBlock{blkG, blk1, blk2, blk3, blk4} {
r, err := blk.Block.HashTreeRoot()
require.NoError(t, err)
state, blkRoot, err := prepareForkchoiceState(ctx, blk.Block.Slot, r, bytesutil.ToBytes32(blk.Block.ParentRoot), [32]byte{}, ojc, ofc)
require.NoError(t, err)
require.NoError(t, service.cfg.ForkChoiceStore.InsertNode(ctx, state, blkRoot))
util.SaveBlock(t, ctx, beaconDB, blk)
}
require.NoError(t, service.saveOrphanedOperations(ctx, r3, r4))
require.Equal(t, 3, service.cfg.AttPool.AggregatedAttestationCount())
wantAtts := []*ethpb.Attestation{
blk3.Block.Body.Attestations[0],
blk2.Block.Body.Attestations[0],
blk1.Block.Body.Attestations[0],
}
atts := service.cfg.AttPool.AggregatedAttestations()
sort.Slice(atts, func(i, j int) bool {
return atts[i].Data.Slot > atts[j].Data.Slot
})
require.DeepEqual(t, wantAtts, atts)
require.Equal(t, 1, len(service.cfg.SlashingPool.PendingProposerSlashings(ctx, st, false)))
require.Equal(t, 1, len(service.cfg.SlashingPool.PendingAttesterSlashings(ctx, st, false)))
exits, err := service.cfg.ExitPool.PendingExits()
require.NoError(t, err)
require.Equal(t, 1, len(exits))
}
func TestSaveOrphanedAtts_CanFilter(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
@@ -373,7 +455,7 @@ func TestSaveOrphanedAtts_CanFilter(t *testing.T) {
require.NoError(t, err)
state, blkRoot, err := prepareForkchoiceState(ctx, blk.Block.Slot, r, bytesutil.ToBytes32(blk.Block.ParentRoot), [32]byte{}, ojc, ofc)
require.NoError(t, err)
require.NoError(t, service.ForkChoicer().InsertNode(ctx, state, blkRoot))
require.NoError(t, service.cfg.ForkChoiceStore.InsertNode(ctx, state, blkRoot))
util.SaveBlock(t, ctx, beaconDB, blk)
}
@@ -431,7 +513,7 @@ func TestSaveOrphanedAtts_DoublyLinkedTrie(t *testing.T) {
require.NoError(t, err)
state, blkRoot, err := prepareForkchoiceState(ctx, blk.Block.Slot, r, bytesutil.ToBytes32(blk.Block.ParentRoot), [32]byte{}, ojc, ofc)
require.NoError(t, err)
require.NoError(t, service.ForkChoicer().InsertNode(ctx, state, blkRoot))
require.NoError(t, service.cfg.ForkChoiceStore.InsertNode(ctx, state, blkRoot))
util.SaveBlock(t, ctx, beaconDB, blk)
}
@@ -490,7 +572,7 @@ func TestSaveOrphanedAtts_CanFilter_DoublyLinkedTrie(t *testing.T) {
require.NoError(t, err)
state, blkRoot, err := prepareForkchoiceState(ctx, blk.Block.Slot, r, bytesutil.ToBytes32(blk.Block.ParentRoot), [32]byte{}, ojc, ofc)
require.NoError(t, err)
require.NoError(t, service.ForkChoicer().InsertNode(ctx, state, blkRoot))
require.NoError(t, service.cfg.ForkChoiceStore.InsertNode(ctx, state, blkRoot))
util.SaveBlock(t, ctx, beaconDB, blk)
}

View File

@@ -108,13 +108,13 @@ func (s *Service) onBlock(ctx context.Context, signed interfaces.ReadOnlySignedB
}
// Verify that the parent block is in forkchoice
if !s.ForkChoicer().HasNode(b.ParentRoot()) {
if !s.cfg.ForkChoiceStore.HasNode(b.ParentRoot()) {
return ErrNotDescendantOfFinalized
}
// Save current justified and finalized epochs for future use.
currStoreJustifiedEpoch := s.ForkChoicer().JustifiedCheckpoint().Epoch
currStoreFinalizedEpoch := s.ForkChoicer().FinalizedCheckpoint().Epoch
currStoreJustifiedEpoch := s.cfg.ForkChoiceStore.JustifiedCheckpoint().Epoch
currStoreFinalizedEpoch := s.cfg.ForkChoiceStore.FinalizedCheckpoint().Epoch
preStateFinalizedEpoch := preState.FinalizedCheckpoint().Epoch
preStateJustifiedEpoch := preState.CurrentJustifiedCheckpoint().Epoch
@@ -187,18 +187,18 @@ func (s *Service) onBlock(ctx context.Context, signed interfaces.ReadOnlySignedB
}()
}
justified := s.ForkChoicer().JustifiedCheckpoint()
justified := s.cfg.ForkChoiceStore.JustifiedCheckpoint()
start := time.Now()
headRoot, err := s.cfg.ForkChoiceStore.Head(ctx)
if err != nil {
log.WithError(err).Warn("Could not update head")
}
if blockRoot != headRoot {
receivedWeight, err := s.ForkChoicer().Weight(blockRoot)
receivedWeight, err := s.cfg.ForkChoiceStore.Weight(blockRoot)
if err != nil {
log.WithField("root", fmt.Sprintf("%#x", blockRoot)).Warn("could not determine node weight")
}
headWeight, err := s.ForkChoicer().Weight(headRoot)
headWeight, err := s.cfg.ForkChoiceStore.Weight(headRoot)
if err != nil {
log.WithField("root", fmt.Sprintf("%#x", headRoot)).Warn("could not determine node weight")
}
@@ -252,7 +252,7 @@ func (s *Service) onBlock(ctx context.Context, signed interfaces.ReadOnlySignedB
// Save finalized check point to db and more.
postStateFinalizedEpoch := postState.FinalizedCheckpoint().Epoch
finalized := s.ForkChoicer().FinalizedCheckpoint()
finalized := s.cfg.ForkChoiceStore.FinalizedCheckpoint()
if finalized.Epoch > currStoreFinalizedEpoch || (finalized.Epoch == postStateFinalizedEpoch && finalized.Epoch > preStateFinalizedEpoch) {
if err := s.updateFinalized(ctx, &ethpb.Checkpoint{Epoch: finalized.Epoch, Root: finalized.Root[:]}); err != nil {
return err
@@ -576,7 +576,7 @@ func (s *Service) InsertSlashingsToForkChoiceStore(ctx context.Context, slashing
for _, slashing := range slashings {
indices := blocks.SlashableAttesterIndices(slashing)
for _, index := range indices {
s.ForkChoicer().InsertSlashedIndex(ctx, primitives.ValidatorIndex(index))
s.cfg.ForkChoiceStore.InsertSlashedIndex(ctx, primitives.ValidatorIndex(index))
}
}
}
@@ -671,12 +671,7 @@ func (s *Service) fillMissingPayloadIDRoutine(ctx context.Context, stateFeed *ev
for {
select {
case <-ticker.C():
s.cfg.StateNotifier.StateFeed().Send(&feed.Event{
Type: statefeed.MissedSlot,
})
if err := s.fillMissingBlockPayloadId(ctx); err != nil {
log.WithError(err).Error("Could not fill missing payload ID")
}
s.lateBlockTasks(ctx)
case <-ctx.Done():
log.Debug("Context closed, exiting routine")
@@ -686,34 +681,47 @@ func (s *Service) fillMissingPayloadIDRoutine(ctx context.Context, stateFeed *ev
}()
}
// fillMissingBlockPayloadId is called 4 seconds into the slot and calls FCU if we are proposing next slot
// and the cache has been missed
func (s *Service) fillMissingBlockPayloadId(ctx context.Context) error {
s.ForkChoicer().RLock()
highestReceivedSlot := s.cfg.ForkChoiceStore.HighestReceivedBlockSlot()
s.ForkChoicer().RUnlock()
if s.CurrentSlot() == highestReceivedSlot {
return nil
// lateBlockTasks is called 4 seconds into the slot and performs tasks
// related to late blocks. It emits a MissedSlot state feed event.
// It calls FCU and sets the right attributes if we are proposing next slot
// it also updates the next slot cache to deal with skipped slots.
func (s *Service) lateBlockTasks(ctx context.Context) {
if s.CurrentSlot() == s.HeadSlot() {
return
}
s.cfg.StateNotifier.StateFeed().Send(&feed.Event{
Type: statefeed.MissedSlot,
})
// Head root should be empty when retrieving proposer index for the next slot.
_, id, has := s.cfg.ProposerSlotIndexCache.GetProposerPayloadIDs(s.CurrentSlot()+1, [32]byte{} /* head root */)
// There exists proposer for next slot, but we haven't called fcu w/ payload attribute yet.
if !has || id != [8]byte{} {
return nil
if (!has && !features.Get().PrepareAllPayloads) || id != [8]byte{} {
return
}
s.headLock.RLock()
headBlock, err := s.headBlock()
if err != nil {
s.headLock.RUnlock()
return err
log.WithError(err).Debug("could not perform late block tasks: failed to retrieve head block")
return
}
headState := s.headState(ctx)
headRoot := s.headRoot()
headState := s.headState(ctx)
s.headLock.RUnlock()
_, err = s.notifyForkchoiceUpdate(ctx, &notifyForkchoiceUpdateArg{
headState: headState,
headRoot: headRoot,
headBlock: headBlock.Block(),
})
return err
if err != nil {
log.WithError(err).Debug("could not perform late block tasks: failed to update forkchoice with engine")
}
lastRoot, lastState := transition.LastCachedState()
if lastState == nil {
lastRoot, lastState = headRoot[:], headState
}
if err = transition.UpdateNextSlotCache(ctx, lastRoot, lastState); err != nil {
log.WithError(err).Debug("could not update next slot state cache")
}
}

View File

@@ -85,7 +85,7 @@ func (s *Service) verifyBlkPreState(ctx context.Context, b interfaces.ReadOnlyBe
// verifyBlkFinalizedSlot validates input block is not less than or equal
// to current finalized slot.
func (s *Service) verifyBlkFinalizedSlot(b interfaces.ReadOnlyBeaconBlock) error {
finalized := s.ForkChoicer().FinalizedCheckpoint()
finalized := s.cfg.ForkChoiceStore.FinalizedCheckpoint()
finalizedSlot, err := slots.EpochStart(finalized.Epoch)
if err != nil {
return err
@@ -146,39 +146,6 @@ func (s *Service) updateFinalized(ctx context.Context, cp *ethpb.Checkpoint) err
return nil
}
// ancestor returns the block root of an ancestry block from the input block root.
//
// Spec pseudocode definition:
//
// def get_ancestor(store: Store, root: Root, slot: Slot) -> Root:
// block = store.blocks[root]
// if block.slot > slot:
// return get_ancestor(store, block.parent_root, slot)
// elif block.slot == slot:
// return root
// else:
// # root is older than queried slot, thus a skip slot. Return most recent root prior to slot
// return root
func (s *Service) ancestor(ctx context.Context, root []byte, slot primitives.Slot) ([]byte, error) {
ctx, span := trace.StartSpan(ctx, "blockChain.ancestor")
defer span.End()
r := bytesutil.ToBytes32(root)
// Get ancestor root from fork choice store instead of recursively looking up blocks in DB.
// This is most optimal outcome.
ar, err := s.cfg.ForkChoiceStore.AncestorRoot(ctx, r, slot)
if err != nil {
// Try getting ancestor root from DB when failed to retrieve from fork choice store.
// This is the second line of defense for retrieving ancestor root.
ar, err = s.ancestorByDB(ctx, r, slot)
if err != nil {
return nil, err
}
}
return ar[:], nil
}
// This retrieves an ancestor root using DB. The look up is recursively looking up DB. Slower than `ancestorByForkChoiceStore`.
func (s *Service) ancestorByDB(ctx context.Context, r [32]byte, slot primitives.Slot) (root [32]byte, err error) {
ctx, span := trace.StartSpan(ctx, "blockChain.ancestorByDB")
@@ -210,7 +177,7 @@ func (s *Service) fillInForkChoiceMissingBlocks(ctx context.Context, blk interfa
pendingNodes := make([]*forkchoicetypes.BlockAndCheckpoints, 0)
// Fork choice only matters from last finalized slot.
finalized := s.ForkChoicer().FinalizedCheckpoint()
finalized := s.cfg.ForkChoiceStore.FinalizedCheckpoint()
fSlot, err := slots.EpochStart(finalized.Epoch)
if err != nil {
return err
@@ -236,7 +203,7 @@ func (s *Service) fillInForkChoiceMissingBlocks(ctx context.Context, blk interfa
if len(pendingNodes) == 1 {
return nil
}
if root != s.ensureRootNotZeros(finalized.Root) && !s.ForkChoicer().HasNode(root) {
if root != s.ensureRootNotZeros(finalized.Root) && !s.cfg.ForkChoiceStore.HasNode(root) {
return ErrNotDescendantOfFinalized
}
return s.cfg.ForkChoiceStore.InsertChain(ctx, pendingNodes)

View File

@@ -27,6 +27,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/attestations"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen"
"github.com/prysmaticlabs/prysm/v4/config/features"
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
"github.com/prysmaticlabs/prysm/v4/config/params"
consensusblocks "github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
@@ -139,7 +140,7 @@ func TestStore_OnBlock(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
fRoot := bytesutil.ToBytes32(roots[0])
require.NoError(t, service.ForkChoicer().UpdateFinalizedCheckpoint(&forkchoicetypes.Checkpoint{Root: fRoot}))
require.NoError(t, service.cfg.ForkChoiceStore.UpdateFinalizedCheckpoint(&forkchoicetypes.Checkpoint{Root: fRoot}))
root, err := tt.blk.Block.HashTreeRoot()
assert.NoError(t, err)
wsb, err := consensusblocks.NewSignedBeaconBlock(tt.blk)
@@ -288,9 +289,9 @@ func TestFillForkChoiceMissingBlocks_CanSave(t *testing.T) {
r0 := bytesutil.ToBytes32(roots[0])
state, blkRoot, err := prepareForkchoiceState(ctx, 0, r0, service.originBlockRoot, [32]byte{}, fcp, fcp)
require.NoError(t, err)
require.NoError(t, service.ForkChoicer().InsertNode(ctx, state, blkRoot))
require.NoError(t, service.cfg.ForkChoiceStore.InsertNode(ctx, state, blkRoot))
fcp2 := &forkchoicetypes.Checkpoint{Epoch: 0, Root: r0}
require.NoError(t, service.ForkChoicer().UpdateFinalizedCheckpoint(fcp2))
require.NoError(t, service.cfg.ForkChoiceStore.UpdateFinalizedCheckpoint(fcp2))
err = service.fillInForkChoiceMissingBlocks(
context.Background(), wsb.Block(), beaconState.FinalizedCheckpoint(), beaconState.CurrentJustifiedCheckpoint())
@@ -339,9 +340,9 @@ func TestFillForkChoiceMissingBlocks_RootsMatch(t *testing.T) {
r0 := bytesutil.ToBytes32(roots[0])
state, blkRoot, err := prepareForkchoiceState(ctx, 0, r0, service.originBlockRoot, [32]byte{}, fcp, fcp)
require.NoError(t, err)
require.NoError(t, service.ForkChoicer().InsertNode(ctx, state, blkRoot))
require.NoError(t, service.cfg.ForkChoiceStore.InsertNode(ctx, state, blkRoot))
fcp2 := &forkchoicetypes.Checkpoint{Epoch: 0, Root: r0}
require.NoError(t, service.ForkChoicer().UpdateFinalizedCheckpoint(fcp2))
require.NoError(t, service.cfg.ForkChoiceStore.UpdateFinalizedCheckpoint(fcp2))
err = service.fillInForkChoiceMissingBlocks(
context.Background(), wsb.Block(), beaconState.FinalizedCheckpoint(), beaconState.CurrentJustifiedCheckpoint())
@@ -406,7 +407,7 @@ func TestFillForkChoiceMissingBlocks_FilterFinalized(t *testing.T) {
beaconState, _ := util.DeterministicGenesisState(t, 32)
// Set finalized epoch to 2.
require.NoError(t, service.ForkChoicer().UpdateFinalizedCheckpoint(&forkchoicetypes.Checkpoint{Epoch: 2, Root: r64}))
require.NoError(t, service.cfg.ForkChoiceStore.UpdateFinalizedCheckpoint(&forkchoicetypes.Checkpoint{Epoch: 2, Root: r64}))
err = service.fillInForkChoiceMissingBlocks(
context.Background(), wsb.Block(), beaconState.FinalizedCheckpoint(), beaconState.CurrentJustifiedCheckpoint())
require.NoError(t, err)
@@ -600,14 +601,14 @@ func TestAncestor_HandleSkipSlot(t *testing.T) {
}
// Slots 100 to 200 are skip slots. Requesting root at 150 will yield root at 100. The last physical block.
r, err := service.ancestor(context.Background(), r200[:], 150)
r, err := service.Ancestor(context.Background(), r200[:], 150)
require.NoError(t, err)
if bytesutil.ToBytes32(r) != r100 {
t.Error("Did not get correct root")
}
// Slots 1 to 100 are skip slots. Requesting root at 50 will yield root at 1. The last physical block.
r, err = service.ancestor(context.Background(), r200[:], 50)
r, err = service.Ancestor(context.Background(), r200[:], 50)
require.NoError(t, err)
if bytesutil.ToBytes32(r) != r1 {
t.Error("Did not get correct root")
@@ -648,7 +649,7 @@ func TestAncestor_CanUseForkchoice(t *testing.T) {
require.NoError(t, service.cfg.ForkChoiceStore.InsertNode(ctx, st, blkRoot))
}
r, err := service.ancestor(context.Background(), r200[:], 150)
r, err := service.Ancestor(context.Background(), r200[:], 150)
require.NoError(t, err)
if bytesutil.ToBytes32(r) != r100 {
t.Error("Did not get correct root")
@@ -696,7 +697,7 @@ func TestAncestor_CanUseDB(t *testing.T) {
require.NoError(t, err)
require.NoError(t, service.cfg.ForkChoiceStore.InsertNode(ctx, st, blkRoot))
r, err := service.ancestor(context.Background(), r200[:], 150)
r, err := service.Ancestor(context.Background(), r200[:], 150)
require.NoError(t, err)
if bytesutil.ToBytes32(r) != r100 {
t.Error("Did not get correct root")
@@ -1363,7 +1364,7 @@ func Test_verifyBlkFinalizedSlot_invalidBlock(t *testing.T) {
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
require.NoError(t, service.ForkChoicer().UpdateFinalizedCheckpoint(&forkchoicetypes.Checkpoint{Epoch: 1}))
require.NoError(t, service.cfg.ForkChoiceStore.UpdateFinalizedCheckpoint(&forkchoicetypes.Checkpoint{Epoch: 1}))
blk := util.HydrateBeaconBlock(&ethpb.BeaconBlock{Slot: 1})
wb, err := consensusblocks.NewBeaconBlock(blk)
require.NoError(t, err)
@@ -1459,7 +1460,7 @@ func TestStore_NoViableHead_FCU(t *testing.T) {
require.NoError(t, err)
}
// Check that we haven't justified the second epoch yet
jc := service.ForkChoicer().JustifiedCheckpoint()
jc := service.cfg.ForkChoiceStore.JustifiedCheckpoint()
require.Equal(t, primitives.Epoch(0), jc.Epoch)
// import a block that justifies the second epoch
@@ -1474,14 +1475,14 @@ func TestStore_NoViableHead_FCU(t *testing.T) {
require.NoError(t, err)
err = service.onBlock(ctx, wsb, firstInvalidRoot)
require.NoError(t, err)
jc = service.ForkChoicer().JustifiedCheckpoint()
jc = service.cfg.ForkChoiceStore.JustifiedCheckpoint()
require.Equal(t, primitives.Epoch(2), jc.Epoch)
sjc := validHeadState.CurrentJustifiedCheckpoint()
require.Equal(t, primitives.Epoch(0), sjc.Epoch)
lvh := b.Block.Body.ExecutionPayload.ParentHash
// check our head
require.Equal(t, firstInvalidRoot, service.ForkChoicer().CachedHeadRoot())
require.Equal(t, firstInvalidRoot, service.cfg.ForkChoiceStore.CachedHeadRoot())
// import another block to find out that it was invalid
mockEngine = &mockExecution.EngineClient{ErrNewPayload: execution.ErrAcceptedSyncingPayloadStatus, ErrForkchoiceUpdated: execution.ErrInvalidPayloadStatus, ForkChoiceUpdatedResp: lvh}
@@ -1500,7 +1501,7 @@ func TestStore_NoViableHead_FCU(t *testing.T) {
// Check that forkchoice's head is the last invalid block imported. The
// store's headroot is the previous head (since the invalid block did
// not finish importing) one and that the node is optimistic
require.Equal(t, root, service.ForkChoicer().CachedHeadRoot())
require.Equal(t, root, service.cfg.ForkChoiceStore.CachedHeadRoot())
headRoot, err := service.HeadRoot(ctx)
require.NoError(t, err)
require.Equal(t, firstInvalidRoot, bytesutil.ToBytes32(headRoot))
@@ -1522,7 +1523,7 @@ func TestStore_NoViableHead_FCU(t *testing.T) {
require.NoError(t, err)
// Check the newly imported block is head, it justified the right
// checkpoint and the node is no longer optimistic
require.Equal(t, root, service.ForkChoicer().CachedHeadRoot())
require.Equal(t, root, service.cfg.ForkChoiceStore.CachedHeadRoot())
sjc = service.CurrentJustifiedCheckpt()
require.Equal(t, jc.Epoch, sjc.Epoch)
require.Equal(t, jc.Root, bytesutil.ToBytes32(sjc.Root))
@@ -1619,7 +1620,7 @@ func TestStore_NoViableHead_NewPayload(t *testing.T) {
require.NoError(t, err)
}
// Check that we haven't justified the second epoch yet
jc := service.ForkChoicer().JustifiedCheckpoint()
jc := service.cfg.ForkChoiceStore.JustifiedCheckpoint()
require.Equal(t, primitives.Epoch(0), jc.Epoch)
// import a block that justifies the second epoch
@@ -1634,14 +1635,14 @@ func TestStore_NoViableHead_NewPayload(t *testing.T) {
require.NoError(t, err)
err = service.onBlock(ctx, wsb, firstInvalidRoot)
require.NoError(t, err)
jc = service.ForkChoicer().JustifiedCheckpoint()
jc = service.cfg.ForkChoiceStore.JustifiedCheckpoint()
require.Equal(t, primitives.Epoch(2), jc.Epoch)
sjc := validHeadState.CurrentJustifiedCheckpoint()
require.Equal(t, primitives.Epoch(0), sjc.Epoch)
lvh := b.Block.Body.ExecutionPayload.ParentHash
// check our head
require.Equal(t, firstInvalidRoot, service.ForkChoicer().CachedHeadRoot())
require.Equal(t, firstInvalidRoot, service.cfg.ForkChoiceStore.CachedHeadRoot())
// import another block to find out that it was invalid
mockEngine = &mockExecution.EngineClient{ErrNewPayload: execution.ErrInvalidPayloadStatus, NewPayloadResp: lvh}
@@ -1660,7 +1661,7 @@ func TestStore_NoViableHead_NewPayload(t *testing.T) {
// Check that forkchoice's head and store's headroot are the previous head (since the invalid block did
// not finish importing and it was never imported to forkchoice). Check
// also that the node is optimistic
require.Equal(t, firstInvalidRoot, service.ForkChoicer().CachedHeadRoot())
require.Equal(t, firstInvalidRoot, service.cfg.ForkChoiceStore.CachedHeadRoot())
headRoot, err := service.HeadRoot(ctx)
require.NoError(t, err)
require.Equal(t, firstInvalidRoot, bytesutil.ToBytes32(headRoot))
@@ -1682,7 +1683,7 @@ func TestStore_NoViableHead_NewPayload(t *testing.T) {
require.NoError(t, err)
// Check the newly imported block is head, it justified the right
// checkpoint and the node is no longer optimistic
require.Equal(t, root, service.ForkChoicer().CachedHeadRoot())
require.Equal(t, root, service.cfg.ForkChoiceStore.CachedHeadRoot())
sjc = service.CurrentJustifiedCheckpt()
require.Equal(t, jc.Epoch, sjc.Epoch)
require.Equal(t, jc.Root, bytesutil.ToBytes32(sjc.Root))
@@ -1802,9 +1803,9 @@ func TestStore_NoViableHead_Liveness(t *testing.T) {
require.NoError(t, err)
}
// Check that we have justified the second epoch
jc := service.ForkChoicer().JustifiedCheckpoint()
jc := service.cfg.ForkChoiceStore.JustifiedCheckpoint()
require.Equal(t, primitives.Epoch(2), jc.Epoch)
invalidHeadRoot := service.ForkChoicer().CachedHeadRoot()
invalidHeadRoot := service.cfg.ForkChoiceStore.CachedHeadRoot()
// import block 19 to find out that the whole chain 13--18 was in fact
// invalid
@@ -1825,7 +1826,7 @@ func TestStore_NoViableHead_Liveness(t *testing.T) {
// Check that forkchoice's head and store's headroot are the previous head (since the invalid block did
// not finish importing and it was never imported to forkchoice). Check
// also that the node is optimistic
require.Equal(t, invalidHeadRoot, service.ForkChoicer().CachedHeadRoot())
require.Equal(t, invalidHeadRoot, service.cfg.ForkChoiceStore.CachedHeadRoot())
headRoot, err := service.HeadRoot(ctx)
require.NoError(t, err)
require.Equal(t, invalidHeadRoot, bytesutil.ToBytes32(headRoot))
@@ -1855,7 +1856,7 @@ func TestStore_NoViableHead_Liveness(t *testing.T) {
require.NoError(t, err)
require.NoError(t, service.onBlock(ctx, wsb, root))
// Check that the head is still INVALID and the node is still optimistic
require.Equal(t, invalidHeadRoot, service.ForkChoicer().CachedHeadRoot())
require.Equal(t, invalidHeadRoot, service.cfg.ForkChoiceStore.CachedHeadRoot())
optimistic, err = service.IsOptimistic(ctx)
require.NoError(t, err)
require.Equal(t, true, optimistic)
@@ -1877,7 +1878,7 @@ func TestStore_NoViableHead_Liveness(t *testing.T) {
require.NoError(t, err)
}
// Head should still be INVALID and the node optimistic
require.Equal(t, invalidHeadRoot, service.ForkChoicer().CachedHeadRoot())
require.Equal(t, invalidHeadRoot, service.cfg.ForkChoiceStore.CachedHeadRoot())
optimistic, err = service.IsOptimistic(ctx)
require.NoError(t, err)
require.Equal(t, true, optimistic)
@@ -1893,7 +1894,7 @@ func TestStore_NoViableHead_Liveness(t *testing.T) {
require.NoError(t, err)
err = service.onBlock(ctx, wsb, root)
require.NoError(t, err)
require.Equal(t, root, service.ForkChoicer().CachedHeadRoot())
require.Equal(t, root, service.cfg.ForkChoiceStore.CachedHeadRoot())
sjc = service.CurrentJustifiedCheckpt()
require.Equal(t, primitives.Epoch(4), sjc.Epoch)
optimistic, err = service.IsOptimistic(ctx)
@@ -2011,7 +2012,7 @@ func TestNoViableHead_Reboot(t *testing.T) {
require.NoError(t, service.onBlock(ctx, wsb, root))
}
// Check that we have justified the second epoch
jc := service.ForkChoicer().JustifiedCheckpoint()
jc := service.cfg.ForkChoiceStore.JustifiedCheckpoint()
require.Equal(t, primitives.Epoch(2), jc.Epoch)
// import block 19 to find out that the whole chain 13--18 was in fact
@@ -2045,7 +2046,7 @@ func TestNoViableHead_Reboot(t *testing.T) {
require.NoError(t, service.StartFromSavedState(genesisState))
// Forkchoice has the genesisRoot loaded at startup
require.Equal(t, genesisRoot, service.ensureRootNotZeros(service.ForkChoicer().CachedHeadRoot()))
require.Equal(t, genesisRoot, service.ensureRootNotZeros(service.cfg.ForkChoiceStore.CachedHeadRoot()))
// Service's store has the finalized state as headRoot
headRoot, err := service.HeadRoot(ctx)
require.NoError(t, err)
@@ -2072,7 +2073,7 @@ func TestNoViableHead_Reboot(t *testing.T) {
// We use onBlockBatch here because the valid chain is missing in forkchoice
require.NoError(t, service.onBlockBatch(ctx, []interfaces.ReadOnlySignedBeaconBlock{wsb}, [][32]byte{root}))
// Check that the head is now VALID and the node is not optimistic
require.Equal(t, genesisRoot, service.ensureRootNotZeros(service.ForkChoicer().CachedHeadRoot()))
require.Equal(t, genesisRoot, service.ensureRootNotZeros(service.cfg.ForkChoiceStore.CachedHeadRoot()))
headRoot, err = service.HeadRoot(ctx)
require.NoError(t, err)
require.Equal(t, root, bytesutil.ToBytes32(headRoot))
@@ -2153,6 +2154,7 @@ func TestOnBlock_HandleBlockAttestations(t *testing.T) {
}
func TestFillMissingBlockPayloadId_DiffSlotExitEarly(t *testing.T) {
logHook := logTest.NewGlobal()
fc := doublylinkedtree.New()
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
@@ -2164,7 +2166,30 @@ func TestFillMissingBlockPayloadId_DiffSlotExitEarly(t *testing.T) {
service, err := NewService(ctx, opts...)
require.NoError(t, err)
require.NoError(t, service.fillMissingBlockPayloadId(ctx), 0)
service.lateBlockTasks(ctx)
require.LogsDoNotContain(t, logHook, "could not perform late block tasks")
}
func TestFillMissingBlockPayloadId_PrepareAllPayloads(t *testing.T) {
logHook := logTest.NewGlobal()
resetCfg := features.InitWithReset(&features.Flags{
PrepareAllPayloads: true,
})
defer resetCfg()
fc := doublylinkedtree.New()
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
opts := []Option{
WithForkChoiceStore(fc),
WithStateGen(stategen.New(beaconDB, fc)),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
service.lateBlockTasks(ctx)
require.LogsDoNotContain(t, logHook, "could not perform late block tasks")
}
// Helper function to simulate the block being on time or delayed for proposer

View File

@@ -56,7 +56,7 @@ func (s *Service) VerifyLmdFfgConsistency(ctx context.Context, a *ethpb.Attestat
if err != nil {
return err
}
r, err := s.ancestor(ctx, a.Data.BeaconBlockRoot, targetSlot)
r, err := s.Ancestor(ctx, a.Data.BeaconBlockRoot, targetSlot)
if err != nil {
return err
}
@@ -100,17 +100,15 @@ func (s *Service) spawnProcessAttestationsRoutine(stateFeed *event.Feed) {
case <-s.ctx.Done():
return
case <-pat.C():
s.ForkChoicer().Lock()
s.UpdateHead(s.ctx, s.CurrentSlot()+1)
s.ForkChoicer().Unlock()
case <-st.C():
s.ForkChoicer().Lock()
if err := s.ForkChoicer().NewSlot(s.ctx, s.CurrentSlot()); err != nil {
s.cfg.ForkChoiceStore.Lock()
if err := s.cfg.ForkChoiceStore.NewSlot(s.ctx, s.CurrentSlot()); err != nil {
log.WithError(err).Error("could not process new slot")
}
s.cfg.ForkChoiceStore.Unlock()
s.UpdateHead(s.ctx, s.CurrentSlot())
s.ForkChoicer().Unlock()
}
}
}()
@@ -120,7 +118,8 @@ func (s *Service) spawnProcessAttestationsRoutine(stateFeed *event.Feed) {
// The caller of this function MUST hold a lock in forkchoice
func (s *Service) UpdateHead(ctx context.Context, proposingSlot primitives.Slot) {
start := time.Now()
s.cfg.ForkChoiceStore.Lock()
defer s.cfg.ForkChoiceStore.Unlock()
// This function is only called at 10 seconds or 0 seconds into the slot
disparity := params.BeaconNetworkConfig().MaximumGossipClockDisparity
if !features.Get().DisableReorgLateBlocks {
@@ -134,6 +133,10 @@ func (s *Service) UpdateHead(ctx context.Context, proposingSlot primitives.Slot)
newHeadRoot, err := s.cfg.ForkChoiceStore.Head(ctx)
if err != nil {
log.WithError(err).Error("Could not compute head from new attestations")
// Fallback to our current head root in the event of a failure.
s.headLock.RLock()
newHeadRoot = s.headRoot()
s.headLock.RUnlock()
}
newAttHeadElapsedTime.Observe(float64(time.Since(start).Milliseconds()))

View File

@@ -67,12 +67,12 @@ func (s *Service) ReceiveBlock(ctx context.Context, block interfaces.ReadOnlySig
}
// Reports on block and fork choice metrics.
cp := s.ForkChoicer().FinalizedCheckpoint()
cp := s.cfg.ForkChoiceStore.FinalizedCheckpoint()
finalized := &ethpb.Checkpoint{Epoch: cp.Epoch, Root: bytesutil.SafeCopyBytes(cp.Root[:])}
reportSlotMetrics(blockCopy.Block().Slot(), s.HeadSlot(), s.CurrentSlot(), finalized)
// Log block sync status.
cp = s.ForkChoicer().JustifiedCheckpoint()
cp = s.cfg.ForkChoiceStore.JustifiedCheckpoint()
justified := &ethpb.Checkpoint{Epoch: cp.Epoch, Root: bytesutil.SafeCopyBytes(cp.Root[:])}
if err := logBlockSyncStatus(blockCopy.Block(), blockRoot, justified, finalized, receivedTime, uint64(s.genesisTime.Unix())); err != nil {
log.WithError(err).Error("Unable to log block sync status")
@@ -123,7 +123,7 @@ func (s *Service) ReceiveBlockBatch(ctx context.Context, blocks []interfaces.Rea
})
// Reports on blockCopy and fork choice metrics.
cp := s.ForkChoicer().FinalizedCheckpoint()
cp := s.cfg.ForkChoiceStore.FinalizedCheckpoint()
finalized := &ethpb.Checkpoint{Epoch: cp.Epoch, Root: bytesutil.SafeCopyBytes(cp.Root[:])}
reportSlotMetrics(blockCopy.Block().Slot(), s.HeadSlot(), s.CurrentSlot(), finalized)
}
@@ -131,7 +131,7 @@ func (s *Service) ReceiveBlockBatch(ctx context.Context, blocks []interfaces.Rea
if err := s.cfg.BeaconDB.SaveBlocks(ctx, s.getInitSyncBlocks()); err != nil {
return err
}
finalized := s.ForkChoicer().FinalizedCheckpoint()
finalized := s.cfg.ForkChoiceStore.FinalizedCheckpoint()
if finalized == nil {
return errNilFinalizedInStore
}
@@ -152,8 +152,8 @@ func (s *Service) HasBlock(ctx context.Context, root [32]byte) bool {
// ReceiveAttesterSlashing receives an attester slashing and inserts it to forkchoice
func (s *Service) ReceiveAttesterSlashing(ctx context.Context, slashing *ethpb.AttesterSlashing) {
s.ForkChoicer().Lock()
defer s.ForkChoicer().Unlock()
s.cfg.ForkChoiceStore.Lock()
defer s.cfg.ForkChoiceStore.Unlock()
s.InsertSlashingsToForkChoiceStore(ctx, []*ethpb.AttesterSlashing{slashing})
}
@@ -179,10 +179,14 @@ func (s *Service) prunePostBlockOperationPools(ctx context.Context, blk interfac
return errors.Wrap(err, "could not process BLSToExecutionChanges")
}
// Mark attester slashings as seen so we don't include same ones in future blocks.
// Mark slashings as seen so we don't include same ones in future blocks.
for _, as := range blk.Block().Body().AttesterSlashings() {
s.cfg.SlashingPool.MarkIncludedAttesterSlashing(as)
}
for _, ps := range blk.Block().Body().ProposerSlashings() {
s.cfg.SlashingPool.MarkIncludedProposerSlashing(ps)
}
return nil
}
@@ -207,7 +211,7 @@ func (s *Service) checkSaveHotStateDB(ctx context.Context) error {
currentEpoch := slots.ToEpoch(s.CurrentSlot())
// Prevent `sinceFinality` going underflow.
var sinceFinality primitives.Epoch
finalized := s.ForkChoicer().FinalizedCheckpoint()
finalized := s.cfg.ForkChoiceStore.FinalizedCheckpoint()
if finalized == nil {
return errNilFinalizedInStore
}

View File

@@ -23,6 +23,8 @@ import (
mockExecution "github.com/prysmaticlabs/prysm/v4/beacon-chain/execution/testing"
doublylinkedtree "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/doubly-linked-tree"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/attestations"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/slashings"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/voluntaryexits"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p"
state_native "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen"
@@ -131,6 +133,8 @@ func setupBeaconChain(t *testing.T, beaconDB db.Database) *Service {
WithDepositCache(depositCache),
WithChainStartFetcher(web3Service),
WithAttestationPool(attestations.NewPool()),
WithSlashingPool(slashings.NewPool()),
WithExitPool(voluntaryexits.NewPool()),
WithP2PBroadcaster(&mockBroadcaster{}),
WithStateNotifier(&mockBeaconNode{}),
WithForkChoiceStore(fc),

View File

@@ -27,6 +27,7 @@ go_library(
"//consensus-types/primitives:go_default_library",
"//encoding/bytesutil:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/eth/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",

View File

@@ -26,6 +26,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
enginev1 "github.com/prysmaticlabs/prysm/v4/proto/engine/v1"
ethpbv1 "github.com/prysmaticlabs/prysm/v4/proto/eth/v1"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
"github.com/sirupsen/logrus"
)
@@ -67,11 +68,12 @@ type ChainService struct {
ReceiveBlockMockErr error
OptimisticCheckRootReceived [32]byte
FinalizedRoots map[[32]byte]bool
OptimisticRoots map[[32]byte]bool
}
// ForkChoicer mocks the same method in the chain service
func (s *ChainService) ForkChoicer() forkchoice.ForkChoicer {
return s.ForkChoiceStore
func (s *ChainService) Ancestor(ctx context.Context, root []byte, slot primitives.Slot) ([]byte, error) {
r, err := s.ForkChoiceStore.AncestorRoot(ctx, bytesutil.ToBytes32(root), slot)
return r[:], err
}
// StateNotifier mocks the same method in the chain service.
@@ -457,7 +459,7 @@ func (s *ChainService) InForkchoice(_ [32]byte) bool {
// IsOptimisticForRoot mocks the same method in the chain service.
func (s *ChainService) IsOptimisticForRoot(_ context.Context, root [32]byte) (bool, error) {
s.OptimisticCheckRootReceived = root
return s.Optimistic, nil
return s.OptimisticRoots[root], nil
}
// UpdateHead mocks the same method in the chain service.
@@ -467,7 +469,7 @@ func (s *ChainService) UpdateHead(ctx context.Context, slot primitives.Slot) {
if err != nil {
logrus.WithError(err).Error("could not update head")
}
err = s.ForkChoicer().InsertNode(ctx, st, root)
err = s.ForkChoiceStore.InsertNode(ctx, st, root)
if err != nil {
logrus.WithError(err).Error("could not insert node to forkchoice")
}
@@ -514,3 +516,84 @@ func prepareForkchoiceState(
st, err := state_native.InitializeFromProtoBellatrix(base)
return st, blockRoot, err
}
// CachedHeadRoot mocks the same method in the chain service
func (s *ChainService) CachedHeadRoot() [32]byte {
if s.ForkChoiceStore != nil {
return s.ForkChoiceStore.CachedHeadRoot()
}
return [32]byte{}
}
// GetProposerHead mocks the same method in the chain service
func (s *ChainService) GetProposerHead() [32]byte {
if s.ForkChoiceStore != nil {
return s.ForkChoiceStore.GetProposerHead()
}
return [32]byte{}
}
// SetForkchoiceGenesisTime mocks the same method in the chain service
func (s *ChainService) SetForkChoiceGenesisTime(timestamp uint64) {
if s.ForkChoiceStore != nil {
s.ForkChoiceStore.SetGenesisTime(timestamp)
}
}
// ReceivedBlocksLastEpoch mocks the same method in the chain service
func (s *ChainService) ReceivedBlocksLastEpoch() (uint64, error) {
if s.ForkChoiceStore != nil {
return s.ForkChoiceStore.ReceivedBlocksLastEpoch()
}
return 0, nil
}
// HighestReceivedBlockSlot mocks the same method in the chain service
func (s *ChainService) HighestReceivedBlockSlot() primitives.Slot {
if s.ForkChoiceStore != nil {
return s.ForkChoiceStore.HighestReceivedBlockSlot()
}
return 0
}
// InsertNode mocks the same method in the chain service
func (s *ChainService) InsertNode(ctx context.Context, st state.BeaconState, root [32]byte) error {
if s.ForkChoiceStore != nil {
return s.ForkChoiceStore.InsertNode(ctx, st, root)
}
return nil
}
// ForkChoiceDump mocks the same method in the chain service
func (s *ChainService) ForkChoiceDump(ctx context.Context) (*ethpbv1.ForkChoiceDump, error) {
if s.ForkChoiceStore != nil {
return s.ForkChoiceStore.ForkChoiceDump(ctx)
}
return nil, nil
}
// NewSlot mocks the same method in the chain service
func (s *ChainService) NewSlot(ctx context.Context, slot primitives.Slot) error {
if s.ForkChoiceStore != nil {
return s.ForkChoiceStore.NewSlot(ctx, slot)
}
return nil
}
// ProposerBoost mocks the same method in the chain service
func (s *ChainService) ProposerBoost() [32]byte {
if s.ForkChoiceStore != nil {
return s.ForkChoiceStore.ProposerBoost()
}
return [32]byte{}
}
// FinalizedBlockHash mocks the same method in the chain service
func (s *ChainService) FinalizedBlockHash() [32]byte {
return [32]byte{}
}
// UnrealizedJustifiedPayloadBlockHash mocks the same method in the chain service
func (s *ChainService) UnrealizedJustifiedPayloadBlockHash() ([32]byte, error) {
return [32]byte{}, nil
}

View File

@@ -78,7 +78,7 @@ func TestService_VerifyWeakSubjectivityRoot(t *testing.T) {
wsVerifier: wv,
}
require.NoError(t, fcs.UpdateFinalizedCheckpoint(&forkchoicetypes.Checkpoint{Epoch: tt.finalizedEpoch}))
cp := s.ForkChoicer().FinalizedCheckpoint()
cp := s.cfg.ForkChoiceStore.FinalizedCheckpoint()
err = s.wsVerifier.VerifyWeakSubjectivity(context.Background(), cp.Epoch)
if tt.wantErr == nil {
require.NoError(t, err)

View File

@@ -77,7 +77,8 @@ func (s *Service) Start() {
}
// Stop halts the service.
func (*Service) Stop() error {
func (s *Service) Stop() error {
s.cancel()
return nil
}
@@ -89,6 +90,9 @@ func (s *Service) SubmitBlindedBlock(ctx context.Context, b interfaces.ReadOnlyS
defer func() {
submitBlindedBlockLatency.Observe(float64(time.Since(start).Milliseconds()))
}()
if s.c == nil {
return nil, ErrNoBuilder
}
return s.c.SubmitBlindedBlock(ctx, b)
}
@@ -101,6 +105,9 @@ func (s *Service) GetHeader(ctx context.Context, slot primitives.Slot, parentHas
defer func() {
getHeaderLatency.Observe(float64(time.Since(start).Milliseconds()))
}()
if s.c == nil {
return nil, ErrNoBuilder
}
return s.c.GetHeader(ctx, slot, parentHash, pubKey)
}
@@ -124,6 +131,9 @@ func (s *Service) RegisterValidator(ctx context.Context, reg []*ethpb.SignedVali
defer func() {
registerValidatorLatency.Observe(float64(time.Since(start).Milliseconds()))
}()
if s.c == nil {
return ErrNoBuilder
}
idxs := make([]primitives.ValidatorIndex, 0)
msgs := make([]*ethpb.ValidatorRegistrationV1, 0)

View File

@@ -37,3 +37,18 @@ func Test_RegisterValidator(t *testing.T) {
require.NoError(t, s.RegisterValidator(ctx, []*eth.SignedValidatorRegistrationV1{{Message: &eth.ValidatorRegistrationV1{Pubkey: pubkey[:], FeeRecipient: feeRecipient[:]}}}))
assert.Equal(t, true, builder.RegisteredVals[pubkey])
}
func Test_BuilderMethodsWithouClient(t *testing.T) {
s, err := NewService(context.Background())
require.NoError(t, err)
assert.Equal(t, false, s.Configured())
_, err = s.GetHeader(context.Background(), 0, [32]byte{}, [48]byte{})
assert.ErrorContains(t, ErrNoBuilder.Error(), err)
_, err = s.SubmitBlindedBlock(context.Background(), nil)
assert.ErrorContains(t, ErrNoBuilder.Error(), err)
err = s.RegisterValidator(context.Background(), nil)
assert.ErrorContains(t, ErrNoBuilder.Error(), err)
}

View File

@@ -265,7 +265,7 @@ func AttestationsDelta(beaconState state.BeaconState, bal *precompute.Balance, v
finalizedEpoch := beaconState.FinalizedCheckpointEpoch()
increment := cfg.EffectiveBalanceIncrement
factor := cfg.BaseRewardFactor
baseRewardMultiplier := increment * factor / math.IntegerSquareRoot(bal.ActiveCurrentEpoch)
baseRewardMultiplier := increment * factor / math.CachedSquareRoot(bal.ActiveCurrentEpoch)
leak := helpers.IsInInactivityLeak(prevEpoch, finalizedEpoch)
// Modified in Altair and Bellatrix.

View File

@@ -58,5 +58,5 @@ func BaseRewardPerIncrement(activeBalance uint64) (uint64, error) {
return 0, errors.New("active balance can't be 0")
}
cfg := params.BeaconConfig()
return cfg.EffectiveBalanceIncrement * cfg.BaseRewardFactor / math.IntegerSquareRoot(activeBalance), nil
return cfg.EffectiveBalanceIncrement * cfg.BaseRewardFactor / math.CachedSquareRoot(activeBalance), nil
}

View File

@@ -72,7 +72,7 @@ func AttestationsDelta(state state.ReadOnlyBeaconState, pBal *Balance, vp []*Val
prevEpoch := time.PrevEpoch(state)
finalizedEpoch := state.FinalizedCheckpointEpoch()
sqrtActiveCurrentEpoch := math.IntegerSquareRoot(pBal.ActiveCurrentEpoch)
sqrtActiveCurrentEpoch := math.CachedSquareRoot(pBal.ActiveCurrentEpoch)
for i, v := range vp {
rewards[i], penalties[i] = attestationDelta(pBal, sqrtActiveCurrentEpoch, v, prevEpoch, finalizedEpoch)
}
@@ -161,7 +161,7 @@ func ProposersDelta(state state.ReadOnlyBeaconState, pBal *Balance, vp []*Valida
rewards := make([]uint64, numofVals)
totalBalance := pBal.ActiveCurrentEpoch
balanceSqrt := math.IntegerSquareRoot(totalBalance)
balanceSqrt := math.CachedSquareRoot(totalBalance)
// Balance square root cannot be 0, this prevents division by 0.
if balanceSqrt == 0 {
balanceSqrt = 1

View File

@@ -19,8 +19,7 @@ const (
Initialized
// Synced is sent when the beacon node has completed syncing and is ready to participate in the network.
Synced
// Reorg is an event sent when the new head state's slot after a block
// transition is lower than its previous head state slot value.
// Reorg is an event sent when the new head is not a descendant of the previous head.
Reorg
// FinalizedCheckpoint event.
FinalizedCheckpoint

View File

@@ -5,15 +5,20 @@ import (
"context"
"sync"
"github.com/pkg/errors"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
types "github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
)
type nextSlotCache struct {
sync.RWMutex
root []byte
state state.BeaconState
sync.Mutex
prevRoot []byte
lastRoot []byte
prevState state.BeaconState
lastState state.BeaconState
}
var (
@@ -29,19 +34,22 @@ var (
})
)
// NextSlotState returns the saved state if the input root matches the root in `nextSlotCache`. Returns nil otherwise.
// This is useful to check before processing slots. With a cache hit, it will return last processed state with slot plus
// one advancement.
func NextSlotState(_ context.Context, root []byte) (state.BeaconState, error) {
nsc.RLock()
defer nsc.RUnlock()
if !bytes.Equal(root, nsc.root) || bytes.Equal(root, []byte{}) {
nextSlotCacheMiss.Inc()
return nil, nil
// NextSlotState returns the saved state for the given blockroot.
// It returns the last updated state if it matches. Otherwise it returns the previously
// updated state if it matches its root. If no root matches it returns nil
func NextSlotState(root []byte, wantedSlot types.Slot) state.BeaconState {
nsc.Lock()
defer nsc.Unlock()
if bytes.Equal(root, nsc.lastRoot) && nsc.lastState.Slot() <= wantedSlot {
nextSlotCacheHit.Inc()
return nsc.lastState.Copy()
}
nextSlotCacheHit.Inc()
// Returning copied state.
return nsc.state.Copy(), nil
if bytes.Equal(root, nsc.prevRoot) && nsc.prevState.Slot() <= wantedSlot {
nextSlotCacheHit.Inc()
return nsc.prevState.Copy()
}
nextSlotCacheMiss.Inc()
return nil
}
// UpdateNextSlotCache updates the `nextSlotCache`. It saves the input state after advancing the state slot by 1
@@ -52,13 +60,25 @@ func UpdateNextSlotCache(ctx context.Context, root []byte, state state.BeaconSta
copied := state.Copy()
copied, err := ProcessSlots(ctx, copied, copied.Slot()+1)
if err != nil {
return err
return errors.Wrap(err, "could not process slots")
}
nsc.Lock()
defer nsc.Unlock()
nsc.root = root
nsc.state = copied
nsc.prevRoot = nsc.lastRoot
nsc.prevState = nsc.lastState
nsc.lastRoot = bytesutil.SafeCopyBytes(root)
nsc.lastState = copied
return nil
}
// LastCachedState returns the last cached state and root in the cache
func LastCachedState() ([]byte, state.BeaconState) {
nsc.Lock()
defer nsc.Unlock()
if nsc.lastState == nil {
return nil, nil
}
return bytesutil.SafeCopyBytes(nsc.lastRoot), nsc.lastState.Copy()
}

View File

@@ -6,6 +6,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/transition"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v4/testing/assert"
"github.com/prysmaticlabs/prysm/v4/testing/require"
"github.com/prysmaticlabs/prysm/v4/testing/util"
)
@@ -13,18 +14,36 @@ import (
func TestTrailingSlotState_RoundTrip(t *testing.T) {
ctx := context.Background()
r := []byte{'a'}
s, err := transition.NextSlotState(ctx, r)
require.NoError(t, err)
s := transition.NextSlotState(r, 0)
require.Equal(t, nil, s)
s, _ = util.DeterministicGenesisState(t, 1)
require.NoError(t, transition.UpdateNextSlotCache(ctx, r, s))
s, err = transition.NextSlotState(ctx, r)
require.NoError(t, err)
s = transition.NextSlotState(r, 1)
require.Equal(t, primitives.Slot(1), s.Slot())
lastRoot, lastState := transition.LastCachedState()
require.DeepEqual(t, r, lastRoot)
require.Equal(t, s.Slot(), lastState.Slot())
require.NoError(t, transition.UpdateNextSlotCache(ctx, r, s))
s, err = transition.NextSlotState(ctx, r)
require.NoError(t, err)
s = transition.NextSlotState(r, 2)
require.Equal(t, primitives.Slot(2), s.Slot())
lastRoot, lastState = transition.LastCachedState()
require.DeepEqual(t, r, lastRoot)
require.Equal(t, s.Slot(), lastState.Slot())
}
func TestTrailingSlotState_StateAdvancedBeyondRequest(t *testing.T) {
ctx := context.Background()
r := []byte{'a'}
s := transition.NextSlotState(r, 0)
require.Equal(t, nil, s)
s, _ = util.DeterministicGenesisState(t, 1)
assert.NoError(t, s.SetSlot(2))
require.NoError(t, transition.UpdateNextSlotCache(ctx, r, s))
s = transition.NextSlotState(r, 1)
require.Equal(t, nil, s)
}

View File

@@ -147,25 +147,15 @@ func ProcessSlotsUsingNextSlotCache(
ctx, span := trace.StartSpan(ctx, "core.state.ProcessSlotsUsingNextSlotCache")
defer span.End()
// Check whether the parent state has been advanced by 1 slot in next slot cache.
nextSlotState, err := NextSlotState(ctx, parentRoot)
if err != nil {
return nil, err
}
cachedStateExists := nextSlotState != nil && !nextSlotState.IsNil()
// If the next slot state is not nil (i.e. cache hit).
// We replace next slot state with parent state.
if cachedStateExists {
nextSlotState := NextSlotState(parentRoot, slot)
if nextSlotState != nil {
parentState = nextSlotState
}
// In the event our cached state has advanced our
// state to the desired slot, we exit early.
if cachedStateExists && parentState.Slot() == slot {
if parentState.Slot() == slot {
return parentState, nil
}
// Since next slot cache only advances state by 1 slot,
// we check if there's more slots that need to process.
var err error
parentState, err = ProcessSlots(ctx, parentState, slot)
if err != nil {
return nil, errors.Wrap(err, "could not process slots")

View File

@@ -30,6 +30,20 @@ import (
"go.opencensus.io/trace"
)
var (
supportedEngineEndpoints = []string{
NewPayloadMethod,
NewPayloadMethodV2,
ForkchoiceUpdatedMethod,
ForkchoiceUpdatedMethodV2,
GetPayloadMethod,
GetPayloadMethodV2,
ExchangeTransitionConfigurationMethod,
GetPayloadBodiesByHashV1,
GetPayloadBodiesByRangeV1,
}
)
const (
// NewPayloadMethod v1 request string for JSON-RPC.
NewPayloadMethod = "engine_newPayloadV1"
@@ -53,6 +67,8 @@ const (
GetPayloadBodiesByHashV1 = "engine_getPayloadBodiesByHashV1"
// GetPayloadBodiesByRangeV1 v1 request string for JSON-RPC.
GetPayloadBodiesByRangeV1 = "engine_getPayloadBodiesByRangeV1"
// ExchangeCapabilities request string for JSON-RPC.
ExchangeCapabilities = "engine_exchangeCapabilities"
// Defines the seconds before timing out engine endpoints with non-block execution semantics.
defaultEngineTimeout = time.Second
)
@@ -278,6 +294,35 @@ func (s *Service) ExchangeTransitionConfiguration(
return nil
}
func (s *Service) ExchangeCapabilities(ctx context.Context) ([]string, error) {
if !features.Get().EnableOptionalEngineMethods {
return nil, errors.New("optional engine methods not enabled")
}
ctx, span := trace.StartSpan(ctx, "powchain.engine-api-client.ExchangeCapabilities")
defer span.End()
result := &pb.ExchangeCapabilities{}
err := s.rpcClient.CallContext(ctx, &result, ExchangeCapabilities, supportedEngineEndpoints)
var unsupported []string
for _, s1 := range supportedEngineEndpoints {
supported := false
for _, s2 := range result.SupportedMethods {
if s1 == s2 {
supported = true
break
}
}
if !supported {
unsupported = append(unsupported, s1)
}
}
if len(unsupported) != 0 {
log.Warnf("Please update client, detected the following unsupported engine methods: %s", unsupported)
}
return result.SupportedMethods, handleRPCError(err)
}
// GetTerminalBlockHash returns the valid terminal block hash based on total difficulty.
//
// Spec code:

View File

@@ -32,6 +32,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/testing/assert"
"github.com/prysmaticlabs/prysm/v4/testing/require"
"github.com/prysmaticlabs/prysm/v4/testing/util"
logTest "github.com/sirupsen/logrus/hooks/test"
"google.golang.org/protobuf/proto"
)
@@ -2320,3 +2321,77 @@ func TestCapella_PayloadBodiesByRange(t *testing.T) {
}
})
}
func Test_ExchangeCapabilities(t *testing.T) {
resetFn := features.InitWithReset(&features.Flags{
EnableOptionalEngineMethods: true,
})
defer resetFn()
t.Run("empty response works", func(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
defer func() {
require.NoError(t, r.Body.Close())
}()
exchangeCapabilities := &pb.ExchangeCapabilities{}
resp := map[string]interface{}{
"jsonrpc": "2.0",
"id": 1,
"result": exchangeCapabilities,
}
err := json.NewEncoder(w).Encode(resp)
require.NoError(t, err)
}))
ctx := context.Background()
logHook := logTest.NewGlobal()
rpcClient, err := rpc.DialHTTP(srv.URL)
require.NoError(t, err)
service := &Service{}
service.rpcClient = rpcClient
results, err := service.ExchangeCapabilities(ctx)
require.NoError(t, err)
require.Equal(t, 0, len(results))
for _, item := range results {
require.NotNil(t, item)
}
assert.LogsContain(t, logHook, "Please update client, detected the following unsupported engine methods:")
})
t.Run("list of items", func(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
defer func() {
require.NoError(t, r.Body.Close())
}()
exchangeCapabilities := &pb.ExchangeCapabilities{
SupportedMethods: []string{"A", "B", "C"},
}
resp := map[string]interface{}{
"jsonrpc": "2.0",
"id": 1,
"result": exchangeCapabilities,
}
err := json.NewEncoder(w).Encode(resp)
require.NoError(t, err)
}))
ctx := context.Background()
rpcClient, err := rpc.DialHTTP(srv.URL)
require.NoError(t, err)
service := &Service{}
service.rpcClient = rpcClient
results, err := service.ExchangeCapabilities(ctx)
require.NoError(t, err)
require.Equal(t, 3, len(results))
for _, item := range results {
require.NotNil(t, item)
}
})
}

View File

@@ -405,8 +405,8 @@ func TestProcessETH2GenesisLog_CorrectNumOfDeposits(t *testing.T) {
web3Service.rpcClient = &mockExecution.RPCClient{Backend: testAcc.Backend}
web3Service.httpLogger = testAcc.Backend
web3Service.latestEth1Data.LastRequestedBlock = 0
web3Service.latestEth1Data.BlockHeight = testAcc.Backend.Blockchain().CurrentBlock().NumberU64()
web3Service.latestEth1Data.BlockTime = testAcc.Backend.Blockchain().CurrentBlock().Time()
web3Service.latestEth1Data.BlockHeight = testAcc.Backend.Blockchain().CurrentBlock().Number.Uint64()
web3Service.latestEth1Data.BlockTime = testAcc.Backend.Blockchain().CurrentBlock().Time
bConfig := params.MinimalSpecConfig().Copy()
bConfig.MinGenesisTime = 0
bConfig.SecondsPerETH1Block = 10
@@ -444,8 +444,8 @@ func TestProcessETH2GenesisLog_CorrectNumOfDeposits(t *testing.T) {
for i := uint64(0); i < params.BeaconConfig().Eth1FollowDistance; i++ {
testAcc.Backend.Commit()
}
web3Service.latestEth1Data.BlockHeight = testAcc.Backend.Blockchain().CurrentBlock().NumberU64()
web3Service.latestEth1Data.BlockTime = testAcc.Backend.Blockchain().CurrentBlock().Time()
web3Service.latestEth1Data.BlockHeight = testAcc.Backend.Blockchain().CurrentBlock().Number.Uint64()
web3Service.latestEth1Data.BlockTime = testAcc.Backend.Blockchain().CurrentBlock().Time
// Set up our subscriber now to listen for the chain started event.
stateChannel := make(chan *feed.Event, 1)
@@ -502,8 +502,8 @@ func TestProcessETH2GenesisLog_LargePeriodOfNoLogs(t *testing.T) {
web3Service.rpcClient = &mockExecution.RPCClient{Backend: testAcc.Backend}
web3Service.httpLogger = testAcc.Backend
web3Service.latestEth1Data.LastRequestedBlock = 0
web3Service.latestEth1Data.BlockHeight = testAcc.Backend.Blockchain().CurrentBlock().NumberU64()
web3Service.latestEth1Data.BlockTime = testAcc.Backend.Blockchain().CurrentBlock().Time()
web3Service.latestEth1Data.BlockHeight = testAcc.Backend.Blockchain().CurrentBlock().Number.Uint64()
web3Service.latestEth1Data.BlockTime = testAcc.Backend.Blockchain().CurrentBlock().Time
bConfig := params.MinimalSpecConfig().Copy()
bConfig.SecondsPerETH1Block = 10
params.OverrideBeaconConfig(bConfig)
@@ -540,14 +540,14 @@ func TestProcessETH2GenesisLog_LargePeriodOfNoLogs(t *testing.T) {
for i := uint64(0); i < 1500; i++ {
testAcc.Backend.Commit()
}
wantedGenesisTime := testAcc.Backend.Blockchain().CurrentBlock().Time()
wantedGenesisTime := testAcc.Backend.Blockchain().CurrentBlock().Time
// Forward the chain to account for the follow distance
for i := uint64(0); i < params.BeaconConfig().Eth1FollowDistance; i++ {
testAcc.Backend.Commit()
}
web3Service.latestEth1Data.BlockHeight = testAcc.Backend.Blockchain().CurrentBlock().NumberU64()
web3Service.latestEth1Data.BlockTime = testAcc.Backend.Blockchain().CurrentBlock().Time()
web3Service.latestEth1Data.BlockHeight = testAcc.Backend.Blockchain().CurrentBlock().Number.Uint64()
web3Service.latestEth1Data.BlockTime = testAcc.Backend.Blockchain().CurrentBlock().Time
// Set the genesis time 500 blocks ahead of the last
// deposit log.

View File

@@ -210,14 +210,14 @@ func TestFollowBlock_OK(t *testing.T) {
web3Service = setDefaultMocks(web3Service)
web3Service.rpcClient = &mockExecution.RPCClient{Backend: testAcc.Backend}
baseHeight := testAcc.Backend.Blockchain().CurrentBlock().NumberU64()
baseHeight := testAcc.Backend.Blockchain().CurrentBlock().Number.Uint64()
// process follow_distance blocks
for i := 0; i < int(params.BeaconConfig().Eth1FollowDistance); i++ {
testAcc.Backend.Commit()
}
// set current height
web3Service.latestEth1Data.BlockHeight = testAcc.Backend.Blockchain().CurrentBlock().NumberU64()
web3Service.latestEth1Data.BlockTime = testAcc.Backend.Blockchain().CurrentBlock().Time()
web3Service.latestEth1Data.BlockHeight = testAcc.Backend.Blockchain().CurrentBlock().Number.Uint64()
web3Service.latestEth1Data.BlockTime = testAcc.Backend.Blockchain().CurrentBlock().Time
h, err := web3Service.followedBlockHeight(context.Background())
require.NoError(t, err)
@@ -229,8 +229,8 @@ func TestFollowBlock_OK(t *testing.T) {
testAcc.Backend.Commit()
}
// set current height
web3Service.latestEth1Data.BlockHeight = testAcc.Backend.Blockchain().CurrentBlock().NumberU64()
web3Service.latestEth1Data.BlockTime = testAcc.Backend.Blockchain().CurrentBlock().Time()
web3Service.latestEth1Data.BlockHeight = testAcc.Backend.Blockchain().CurrentBlock().Number.Uint64()
web3Service.latestEth1Data.BlockTime = testAcc.Backend.Blockchain().CurrentBlock().Time
h, err = web3Service.followedBlockHeight(context.Background())
require.NoError(t, err)

View File

@@ -4,7 +4,6 @@ go_library(
name = "go_default_library",
testonly = True,
srcs = [
"genesis.go",
"mock_engine_client.go",
"mock_execution_chain.go",
"mock_faulty_powchain.go",
@@ -30,9 +29,7 @@ go_library(
"@com_github_ethereum_go_ethereum//accounts/abi/bind/backends:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
"@com_github_ethereum_go_ethereum//core:go_default_library",
"@com_github_ethereum_go_ethereum//core/types:go_default_library",
"@com_github_ethereum_go_ethereum//params:go_default_library",
"@com_github_ethereum_go_ethereum//rpc:go_default_library",
"@com_github_holiman_uint256//:go_default_library",
"@com_github_pkg_errors//:go_default_library",

View File

@@ -508,6 +508,17 @@ func (f *ForkChoice) JustifiedPayloadBlockHash() [32]byte {
return node.payloadHash
}
// UnrealizedJustifiedPayloadBlockHash returns the hash of the payload at the unrealized justified checkpoint
func (f *ForkChoice) UnrealizedJustifiedPayloadBlockHash() ([32]byte, error) {
root := f.store.unrealizedJustifiedCheckpoint.Root
node, ok := f.store.nodeByRoot[root]
if !ok || node == nil {
// This should not happen
return [32]byte{}, ErrNilNode
}
return node.payloadHash, nil
}
// ForkChoiceDump returns a full dump of forkchoice.
func (f *ForkChoice) ForkChoiceDump(ctx context.Context) (*v1.ForkChoiceDump, error) {
jc := &v1.Checkpoint{

View File

@@ -740,5 +740,22 @@ func TestForkchoice_UpdateJustifiedBalances(t *testing.T) {
require.Equal(t, uint64(7), f.numActiveValidators)
require.Equal(t, uint64(430)/32, f.store.committeeWeight)
require.DeepEqual(t, balances, f.justifiedBalances)
}
func TestForkChoice_UnrealizedJustifiedPayloadBlockHash(t *testing.T) {
ctx := context.Background()
f := setup(0, 0)
st, blkRoot, err := prepareForkchoiceState(ctx, 0, [32]byte{'a'}, params.BeaconConfig().ZeroHash, [32]byte{'A'}, 1, 1)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, st, blkRoot))
f.store.unrealizedJustifiedCheckpoint.Root = [32]byte{'a'}
got, err := f.UnrealizedJustifiedPayloadBlockHash()
require.NoError(t, err)
require.Equal(t, [32]byte{'A'}, got)
f.store.unrealizedJustifiedCheckpoint.Root = [32]byte{'b'}
_, err = f.UnrealizedJustifiedPayloadBlockHash()
require.ErrorIs(t, err, ErrNilNode)
}

View File

@@ -57,6 +57,7 @@ type Getter interface {
JustifiedCheckpoint() *forkchoicetypes.Checkpoint
PreviousJustifiedCheckpoint() *forkchoicetypes.Checkpoint
JustifiedPayloadBlockHash() [32]byte
UnrealizedJustifiedPayloadBlockHash() ([32]byte, error)
NodeCount() int
HighestReceivedBlockSlot() primitives.Slot
ReceivedBlocksLastEpoch() (uint64, error)

View File

@@ -61,8 +61,10 @@ go_library(
"//runtime/prereqs:go_default_library",
"//runtime/version:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_gorilla_mux//:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_prometheus_client_golang//prometheus:go_default_library",
"@com_github_prysmaticlabs_fastssz//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@com_github_urfave_cli_v2//:go_default_library",
],

View File

@@ -4,6 +4,7 @@ import (
"fmt"
"github.com/ethereum/go-ethereum/common"
fastssz "github.com/prysmaticlabs/fastssz"
"github.com/prysmaticlabs/prysm/v4/cmd"
"github.com/prysmaticlabs/prysm/v4/cmd/beacon-chain/flags"
"github.com/prysmaticlabs/prysm/v4/config/params"
@@ -66,6 +67,13 @@ func configureBuilderCircuitBreaker(cliCtx *cli.Context) error {
return err
}
}
if cliCtx.IsSet(flags.LocalBlockValueBoost.Name) {
c := params.BeaconConfig().Copy()
c.LocalBlockValueBoost = cliCtx.Uint64(flags.LocalBlockValueBoost.Name)
if err := params.SetActive(c); err != nil {
return err
}
}
return nil
}
@@ -189,3 +197,7 @@ func configureExecutionSetting(cliCtx *cli.Context) error {
" Default fee recipient will be used as a fall back", checksumAddress.Hex())
return params.SetActive(c)
}
func configureFastSSZHashingAlgorithm() {
fastssz.EnableVectorizedHTR = true
}

View File

@@ -15,6 +15,7 @@ import (
"syscall"
"github.com/ethereum/go-ethereum/common"
"github.com/gorilla/mux"
"github.com/pkg/errors"
apigateway "github.com/prysmaticlabs/prysm/v4/api/gateway"
"github.com/prysmaticlabs/prysm/v4/async/event"
@@ -148,6 +149,7 @@ func New(cliCtx *cli.Context, opts ...Option) (*BeaconNode, error) {
if err := configureExecutionSetting(cliCtx); err != nil {
return nil, err
}
configureFastSSZHashingAlgorithm()
// Initializes any forks here.
params.BeaconConfig().InitializeForkSchedule()
@@ -231,7 +233,7 @@ func New(cliCtx *cli.Context, opts ...Option) (*BeaconNode, error) {
return nil, err
}
log.Debugln("Registering Intial Sync Service")
log.Debugln("Registering Initial Sync Service")
if err := beacon.registerInitialSyncService(); err != nil {
return nil, err
}
@@ -252,12 +254,13 @@ func New(cliCtx *cli.Context, opts ...Option) (*BeaconNode, error) {
}
log.Debugln("Registering RPC Service")
if err := beacon.registerRPCService(); err != nil {
router := mux.NewRouter()
if err := beacon.registerRPCService(router); err != nil {
return nil, err
}
log.Debugln("Registering GRPC Gateway Service")
if err := beacon.registerGRPCGateway(); err != nil {
if err := beacon.registerGRPCGateway(router); err != nil {
return nil, err
}
@@ -535,6 +538,7 @@ func (b *BeaconNode) registerP2P(cliCtx *cli.Context) error {
HostAddress: cliCtx.String(cmd.P2PHost.Name),
HostDNS: cliCtx.String(cmd.P2PHostDNS.Name),
PrivateKey: cliCtx.String(cmd.P2PPrivKey.Name),
StaticPeerID: cliCtx.Bool(cmd.P2PStaticID.Name),
MetaDataDir: cliCtx.String(cmd.P2PMetadata.Name),
TCPPort: cliCtx.Uint(cmd.P2PTCPPort.Name),
UDPPort: cliCtx.Uint(cmd.P2PUDPPort.Name),
@@ -733,7 +737,7 @@ func (b *BeaconNode) registerSlasherService() error {
return b.services.RegisterService(slasherSrv)
}
func (b *BeaconNode) registerRPCService() error {
func (b *BeaconNode) registerRPCService(router *mux.Router) error {
var chainService *blockchain.Service
if err := b.services.FetchService(&chainService); err != nil {
return err
@@ -798,10 +802,10 @@ func (b *BeaconNode) registerRPCService() error {
PeerManager: p2pService,
MetadataProvider: p2pService,
ChainInfoFetcher: chainService,
HeadUpdater: chainService,
HeadFetcher: chainService,
CanonicalFetcher: chainService,
ForkFetcher: chainService,
ForkchoiceFetcher: chainService,
FinalizationFetcher: chainService,
BlockReceiver: chainService,
AttestationReceiver: chainService,
@@ -829,6 +833,7 @@ func (b *BeaconNode) registerRPCService() error {
MaxMsgSize: maxMsgSize,
ProposerIdsCache: b.proposerIdsCache,
BlockBuilder: b.fetchBuilderService(),
Router: router,
})
return b.services.RegisterService(rpcService)
@@ -857,7 +862,7 @@ func (b *BeaconNode) registerPrometheusService(_ *cli.Context) error {
return b.services.RegisterService(service)
}
func (b *BeaconNode) registerGRPCGateway() error {
func (b *BeaconNode) registerGRPCGateway(router *mux.Router) error {
if b.cliCtx.Bool(flags.DisableGRPCGateway.Name) {
return nil
}
@@ -883,6 +888,7 @@ func (b *BeaconNode) registerGRPCGateway() error {
}
opts := []apigateway.Option{
apigateway.WithRouter(router),
apigateway.WithGatewayAddr(gatewayAddress),
apigateway.WithRemoteAddr(selfAddress),
apigateway.WithPbHandlers(muxs),

View File

@@ -24,6 +24,7 @@ go_library(
"options.go",
"pubsub.go",
"pubsub_filter.go",
"pubsub_tracer.go",
"rpc_topic_mappings.go",
"sender.go",
"service.go",
@@ -84,6 +85,7 @@ go_library(
"@com_github_libp2p_go_libp2p//core/host:go_default_library",
"@com_github_libp2p_go_libp2p//core/network:go_default_library",
"@com_github_libp2p_go_libp2p//core/peer:go_default_library",
"@com_github_libp2p_go_libp2p//core/peerstore:go_default_library",
"@com_github_libp2p_go_libp2p//core/protocol:go_default_library",
"@com_github_libp2p_go_libp2p//p2p/muxer/mplex:go_default_library",
"@com_github_libp2p_go_libp2p//p2p/security/noise:go_default_library",

View File

@@ -10,6 +10,7 @@ import (
type Config struct {
NoDiscovery bool
EnableUPnP bool
StaticPeerID bool
StaticPeers []string
BootstrapNodeAddr []string
Discv5BootStrapAddr []string

View File

@@ -332,7 +332,7 @@ func (s *Service) isPeerAtLimit(inbound bool) bool {
return activePeers >= maxPeers || numOfConns >= maxPeers
}
// PeersFromStringAddrs convers peer raw ENRs into multiaddrs for p2p.
// PeersFromStringAddrs converts peer raw ENRs into multiaddrs for p2p.
func PeersFromStringAddrs(addrs []string) ([]ma.Multiaddr, error) {
var allAddrs []ma.Multiaddr
enodeString, multiAddrString := parseGenericAddrs(addrs)

View File

@@ -4,6 +4,7 @@ import (
"strings"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/core/peerstore"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
)
@@ -63,6 +64,80 @@ var (
Name: "p2p_sync_committee_subnet_attempted_broadcasts",
Help: "The number of sync committee that were attempted to be broadcast.",
})
// Gossip Tracer Metrics
pubsubTopicsActive = promauto.NewGaugeVec(prometheus.GaugeOpts{
Name: "p2p_pubsub_topic_active",
Help: "The topics that the peer is participating in gossipsub.",
},
[]string{"topic"})
pubsubTopicsGraft = promauto.NewCounterVec(prometheus.CounterOpts{
Name: "p2p_pubsub_graft_total",
Help: "The number of graft messages sent for a particular topic",
},
[]string{"topic"})
pubsubTopicsPrune = promauto.NewCounterVec(prometheus.CounterOpts{
Name: "p2p_pubsub_prune_total",
Help: "The number of prune messages sent for a particular topic",
},
[]string{"topic"})
pubsubMessageDeliver = promauto.NewCounterVec(prometheus.CounterOpts{
Name: "p2p_pubsub_deliver_total",
Help: "The number of messages received for delivery of a particular topic",
},
[]string{"topic"})
pubsubMessageUndeliverable = promauto.NewCounterVec(prometheus.CounterOpts{
Name: "p2p_pubsub_undeliverable_total",
Help: "The number of messages received which weren't able to be delivered of a particular topic",
},
[]string{"topic"})
pubsubMessageValidate = promauto.NewCounterVec(prometheus.CounterOpts{
Name: "p2p_pubsub_validate_total",
Help: "The number of messages received for validation of a particular topic",
},
[]string{"topic"})
pubsubMessageDuplicate = promauto.NewCounterVec(prometheus.CounterOpts{
Name: "p2p_pubsub_duplicate_total",
Help: "The number of duplicate messages sent for a particular topic",
},
[]string{"topic"})
pubsubMessageReject = promauto.NewCounterVec(prometheus.CounterOpts{
Name: "p2p_pubsub_reject_total",
Help: "The number of messages rejected of a particular topic",
},
[]string{"topic"})
pubsubPeerThrottle = promauto.NewCounterVec(prometheus.CounterOpts{
Name: "p2p_pubsub_throttle_total",
Help: "The number of times a peer has been throttled for a particular topic",
},
[]string{"topic"})
pubsubRPCRecv = promauto.NewCounterVec(prometheus.CounterOpts{
Name: "p2p_pubsub_rpc_recv_total",
Help: "The number of messages received via rpc for a particular topic",
},
[]string{"control_message"})
pubsubRPCSubRecv = promauto.NewCounter(prometheus.CounterOpts{
Name: "p2p_pubsub_rpc_recv_sub_total",
Help: "The number of subscription messages received via rpc",
})
pubsubRPCDrop = promauto.NewCounterVec(prometheus.CounterOpts{
Name: "p2p_pubsub_rpc_drop_total",
Help: "The number of messages dropped via rpc for a particular topic",
},
[]string{"control_message"})
pubsubRPCSubDrop = promauto.NewCounter(prometheus.CounterOpts{
Name: "p2p_pubsub_rpc_drop_sub_total",
Help: "The number of subscription messages dropped via rpc",
})
pubsubRPCSent = promauto.NewCounterVec(prometheus.CounterOpts{
Name: "p2p_pubsub_rpc_sent_total",
Help: "The number of messages sent via rpc for a particular topic",
},
[]string{"control_message"})
pubsubRPCSubSent = promauto.NewCounter(prometheus.CounterOpts{
Name: "p2p_pubsub_rpc_sent_sub_total",
Help: "The number of subscription messages sent via rpc",
})
)
func (s *Service) updateMetrics() {
@@ -84,20 +159,7 @@ func (s *Service) updateMetrics() {
continue
}
// Get the agent data.
rawAgent, err := store.Get(pid, "AgentVersion")
agent, ok := rawAgent.(string)
if err != nil || !ok {
agent = "unknown"
}
foundName := "unknown"
for _, knownAgent := range knownAgentVersions {
// If the agent string matches one of our known agents, we set
// the value to our own, sanitized string.
if strings.Contains(strings.ToLower(agent), knownAgent) {
foundName = knownAgent
}
}
foundName := agentFromPid(pid, store)
numConnectedPeersByClient[foundName] += 1
// Get peer scoring data.
@@ -123,3 +185,21 @@ func average(xs []float64) float64 {
}
return total / float64(len(xs))
}
func agentFromPid(pid peer.ID, store peerstore.Peerstore) string {
// Get the agent data.
rawAgent, err := store.Get(pid, "AgentVersion")
agent, ok := rawAgent.(string)
if err != nil || !ok {
return "unknown"
}
foundName := "unknown"
for _, knownAgent := range knownAgentVersions {
// If the agent string matches one of our known agents, we set
// the value to our own, sanitized string.
if strings.Contains(strings.ToLower(agent), knownAgent) {
foundName = knownAgent
}
}
return foundName
}

View File

@@ -5,6 +5,7 @@ import (
"encoding/hex"
"net"
"os"
"path"
"testing"
gethCrypto "github.com/ethereum/go-ethereum/crypto"
@@ -50,6 +51,32 @@ func TestPrivateKeyLoading(t *testing.T) {
assert.DeepEqual(t, rawBytes, newRaw, "Private keys do not match")
}
func TestPrivateKeyLoading_StaticPrivateKey(t *testing.T) {
params.SetupTestConfigCleanup(t)
tempDir := t.TempDir()
cfg := &Config{
StaticPeerID: true,
DataDir: tempDir,
}
pKey, err := privKey(cfg)
require.NoError(t, err, "Could not apply option")
newPkey, err := ecdsaprysm.ConvertToInterfacePrivkey(pKey)
require.NoError(t, err)
retrievedKey, err := privKeyFromFile(path.Join(tempDir, keyPath))
require.NoError(t, err)
retrievedPKey, err := ecdsaprysm.ConvertToInterfacePrivkey(retrievedKey)
require.NoError(t, err)
rawBytes, err := retrievedPKey.Raw()
require.NoError(t, err)
newRaw, err := newPkey.Raw()
require.NoError(t, err)
assert.DeepEqual(t, rawBytes, newRaw, "Private keys do not match")
}
func TestIPV6Support(t *testing.T) {
params.SetupTestConfigCleanup(t)
key, err := gethCrypto.GenerateKey()

View File

@@ -145,6 +145,7 @@ func (s *Service) pubsubOptions() []pubsub.Option {
pubsub.WithPeerScore(peerScoringParams()),
pubsub.WithPeerScoreInspect(s.peerInspector, time.Minute),
pubsub.WithGossipSubParams(pubsubGossipParam()),
pubsub.WithRawTracer(gossipTracer{host: s.host}),
}
return psOpts
}

View File

@@ -0,0 +1,103 @@
package p2p
import (
pubsub "github.com/libp2p/go-libp2p-pubsub"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/core/protocol"
"github.com/prometheus/client_golang/prometheus"
)
var _ = pubsub.RawTracer(gossipTracer{})
// This tracer is used to implement metrics collection for messages received
// and broadcasted through gossipsub.
type gossipTracer struct {
host host.Host
}
// AddPeer .
func (g gossipTracer) AddPeer(p peer.ID, proto protocol.ID) {
// no-op
}
// RemovePeer .
func (g gossipTracer) RemovePeer(p peer.ID) {
// no-op
}
// Join .
func (g gossipTracer) Join(topic string) {
pubsubTopicsActive.WithLabelValues(topic).Set(1)
}
// Leave .
func (g gossipTracer) Leave(topic string) {
pubsubTopicsActive.WithLabelValues(topic).Set(0)
}
// Graft .
func (g gossipTracer) Graft(p peer.ID, topic string) {
pubsubTopicsGraft.WithLabelValues(topic).Inc()
}
// Prune .
func (g gossipTracer) Prune(p peer.ID, topic string) {
pubsubTopicsPrune.WithLabelValues(topic).Inc()
}
// ValidateMessage .
func (g gossipTracer) ValidateMessage(msg *pubsub.Message) {
pubsubMessageValidate.WithLabelValues(*msg.Topic).Inc()
}
// DeliverMessage .
func (g gossipTracer) DeliverMessage(msg *pubsub.Message) {
pubsubMessageDeliver.WithLabelValues(*msg.Topic).Inc()
}
// RejectMessage .
func (g gossipTracer) RejectMessage(msg *pubsub.Message, reason string) {
pubsubMessageReject.WithLabelValues(*msg.Topic).Inc()
}
// DuplicateMessage .
func (g gossipTracer) DuplicateMessage(msg *pubsub.Message) {
pubsubMessageDuplicate.WithLabelValues(*msg.Topic).Inc()
}
// UndeliverableMessage .
func (g gossipTracer) UndeliverableMessage(msg *pubsub.Message) {
pubsubMessageUndeliverable.WithLabelValues(*msg.Topic).Inc()
}
// ThrottlePeer .
func (g gossipTracer) ThrottlePeer(p peer.ID) {
agent := agentFromPid(p, g.host.Peerstore())
pubsubPeerThrottle.WithLabelValues(agent).Inc()
}
// RecvRPC .
func (g gossipTracer) RecvRPC(rpc *pubsub.RPC) {
setMetricFromRPC(pubsubRPCSubRecv, pubsubRPCRecv, rpc)
}
// SendRPC .
func (g gossipTracer) SendRPC(rpc *pubsub.RPC, p peer.ID) {
setMetricFromRPC(pubsubRPCSubSent, pubsubRPCSent, rpc)
}
// DropRPC .
func (g gossipTracer) DropRPC(rpc *pubsub.RPC, p peer.ID) {
setMetricFromRPC(pubsubRPCSubDrop, pubsubRPCDrop, rpc)
}
func setMetricFromRPC(ctr prometheus.Counter, gauge *prometheus.CounterVec, rpc *pubsub.RPC) {
ctr.Add(float64(len(rpc.Subscriptions)))
if rpc.Control != nil {
gauge.WithLabelValues("graft").Add(float64(len(rpc.Control.Graft)))
gauge.WithLabelValues("prune").Add(float64(len(rpc.Control.Prune)))
gauge.WithLabelValues("ihave").Add(float64(len(rpc.Control.Ihave)))
gauge.WithLabelValues("iwant").Add(float64(len(rpc.Control.Iwant)))
}
}

View File

@@ -272,7 +272,7 @@ func (p *TestP2P) AddConnectionHandler(f, _ func(ctx context.Context, id peer.ID
p.peers.SetConnectionState(conn.RemotePeer(), peers.PeerConnecting)
if err := f(ctx, conn.RemotePeer()); err != nil {
logrus.WithError(err).Error("Could not send succesful hello rpc request")
logrus.WithError(err).Error("Could not send successful hello rpc request")
if err := p.Disconnect(conn.RemotePeer()); err != nil {
logrus.WithError(err).Errorf("Unable to close peer %s", conn.RemotePeer())
}

View File

@@ -49,23 +49,43 @@ func privKey(cfg *Config) (*ecdsa.PrivateKey, error) {
defaultKeyPath := path.Join(cfg.DataDir, keyPath)
privateKeyPath := cfg.PrivateKey
// PrivateKey cli flag takes highest precedence.
if privateKeyPath != "" {
return privKeyFromFile(cfg.PrivateKey)
}
_, err := os.Stat(defaultKeyPath)
defaultKeysExist := !os.IsNotExist(err)
if err != nil && defaultKeysExist {
return nil, err
}
if privateKeyPath == "" && !defaultKeysExist {
priv, _, err := crypto.GenerateSecp256k1Key(rand.Reader)
// Default keys have the next highest precedence, if they exist.
if defaultKeysExist {
return privKeyFromFile(defaultKeyPath)
}
// There are no keys on the filesystem, so we need to generate one.
priv, _, err := crypto.GenerateSecp256k1Key(rand.Reader)
if err != nil {
return nil, err
}
// If the StaticPeerID flag is set, save the generated key as the default
// key, so that it will be used by default on the next node start.
if cfg.StaticPeerID {
rawbytes, err := priv.Raw()
if err != nil {
return nil, err
}
return ecdsaprysm.ConvertFromInterfacePrivKey(priv)
dst := make([]byte, hex.EncodedLen(len(rawbytes)))
hex.Encode(dst, rawbytes)
if err := file.WriteFile(defaultKeyPath, dst); err != nil {
return nil, err
}
log.Infof("Wrote network key to file")
// Read the key from the defaultKeyPath file just written
// for the strongest guarantee that the next start will be the same as this one.
return privKeyFromFile(defaultKeyPath)
}
if defaultKeysExist && privateKeyPath == "" {
privateKeyPath = defaultKeyPath
}
return privKeyFromFile(privateKeyPath)
return ecdsaprysm.ConvertFromInterfacePrivKey(priv)
}
// Retrieves a p2p networking private key from a file path.

View File

@@ -28,12 +28,13 @@ go_library(
"//beacon-chain/rpc/eth/debug:go_default_library",
"//beacon-chain/rpc/eth/events:go_default_library",
"//beacon-chain/rpc/eth/node:go_default_library",
"//beacon-chain/rpc/eth/rewards:go_default_library",
"//beacon-chain/rpc/eth/validator:go_default_library",
"//beacon-chain/rpc/lookup:go_default_library",
"//beacon-chain/rpc/prysm/v1alpha1/beacon:go_default_library",
"//beacon-chain/rpc/prysm/v1alpha1/debug:go_default_library",
"//beacon-chain/rpc/prysm/v1alpha1/node:go_default_library",
"//beacon-chain/rpc/prysm/v1alpha1/validator:go_default_library",
"//beacon-chain/rpc/statefetcher:go_default_library",
"//beacon-chain/slasher:go_default_library",
"//beacon-chain/state/stategen:go_default_library",
"//beacon-chain/sync:go_default_library",
@@ -43,6 +44,7 @@ go_library(
"//monitoring/tracing:go_default_library",
"//proto/eth/service:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"@com_github_gorilla_mux//:go_default_library",
"@com_github_grpc_ecosystem_go_grpc_middleware//:go_default_library",
"@com_github_grpc_ecosystem_go_grpc_middleware//recovery:go_default_library",
"@com_github_grpc_ecosystem_go_grpc_middleware//tracing/opentracing:go_default_library",
@@ -68,6 +70,7 @@ go_test(
"//beacon-chain/sync/initial-sync/testing:go_default_library",
"//testing/assert:go_default_library",
"//testing/require:go_default_library",
"@com_github_gorilla_mux//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
],

View File

@@ -1185,7 +1185,7 @@ type EventPayloadAttributeV2Json struct {
ParentBlockNumber string `json:"parent_block_number"`
ParentBlockRoot string `json:"parent_block_root" hex:"true"`
ParentBlockHash string `json:"parent_block_hash" hex:"true"`
PayloadAttributes *PayloadAttributesV2Json `json:"payload_attributes_v2"`
PayloadAttributes *PayloadAttributesV2Json `json:"payload_attributes"`
}
type PayloadAttributesV1Json struct {

View File

@@ -34,8 +34,8 @@ go_library(
"//beacon-chain/operations/voluntaryexits:go_default_library",
"//beacon-chain/p2p:go_default_library",
"//beacon-chain/rpc/eth/helpers:go_default_library",
"//beacon-chain/rpc/lookup:go_default_library",
"//beacon-chain/rpc/prysm/v1alpha1/validator:go_default_library",
"//beacon-chain/rpc/statefetcher:go_default_library",
"//beacon-chain/state:go_default_library",
"//beacon-chain/state/state-native:go_default_library",
"//beacon-chain/state/stategen:go_default_library",
@@ -92,7 +92,6 @@ go_test(
"//beacon-chain/core/transition:go_default_library",
"//beacon-chain/db:go_default_library",
"//beacon-chain/db/testing:go_default_library",
"//beacon-chain/execution/testing:go_default_library",
"//beacon-chain/operations/attestations:go_default_library",
"//beacon-chain/operations/blstoexec:go_default_library",
"//beacon-chain/operations/blstoexec/mock:go_default_library",
@@ -101,12 +100,11 @@ go_test(
"//beacon-chain/operations/voluntaryexits/mock:go_default_library",
"//beacon-chain/p2p/testing:go_default_library",
"//beacon-chain/rpc/eth/helpers:go_default_library",
"//beacon-chain/rpc/lookup:go_default_library",
"//beacon-chain/rpc/prysm/v1alpha1/validator:go_default_library",
"//beacon-chain/rpc/statefetcher:go_default_library",
"//beacon-chain/rpc/testutil:go_default_library",
"//beacon-chain/state:go_default_library",
"//beacon-chain/state/state-native:go_default_library",
"//config/features:go_default_library",
"//config/params:go_default_library",
"//consensus-types/blocks:go_default_library",
"//consensus-types/interfaces:go_default_library",

View File

@@ -25,7 +25,7 @@ func (bs *Server) GetBlindedBlock(ctx context.Context, req *ethpbv1.BlockRequest
ctx, span := trace.StartSpan(ctx, "beacon.GetBlindedBlock")
defer span.End()
blk, err := bs.blockFromBlockID(ctx, req.BlockId)
blk, err := bs.Blocker.Block(ctx, req.BlockId)
err = handleGetBlockError(blk, err)
if err != nil {
return nil, err
@@ -80,7 +80,7 @@ func (bs *Server) GetBlindedBlockSSZ(ctx context.Context, req *ethpbv1.BlockRequ
ctx, span := trace.StartSpan(ctx, "beacon.GetBlindedBlockSSZ")
defer span.End()
blk, err := bs.blockFromBlockID(ctx, req.BlockId)
blk, err := bs.Blocker.Block(ctx, req.BlockId)
err = handleGetBlockError(blk, err)
if err != nil {
return nil, err

View File

@@ -2,17 +2,15 @@ package beacon
import (
"context"
"fmt"
"reflect"
"testing"
mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing"
builderTest "github.com/prysmaticlabs/prysm/v4/beacon-chain/builder/testing"
dbTest "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing"
executionTest "github.com/prysmaticlabs/prysm/v4/beacon-chain/execution/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/synccommittee"
mockp2p "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/prysm/v1alpha1/validator"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/testutil"
"github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
@@ -21,7 +19,6 @@ import (
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"
ethpbalpha "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v4/testing/assert"
"github.com/prysmaticlabs/prysm/v4/testing/require"
"github.com/prysmaticlabs/prysm/v4/testing/util"
@@ -29,770 +26,284 @@ import (
)
func TestServer_GetBlindedBlock(t *testing.T) {
ctx := context.Background()
t.Run("Phase 0", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
genBlk, blkContainers := fillDBTestBlocks(ctx, t, beaconDB)
canonicalRoots := make(map[[32]byte]bool)
for _, bContr := range blkContainers {
canonicalRoots[bytesutil.ToBytes32(bContr.BlockRoot)] = true
}
headBlock := blkContainers[len(blkContainers)-1]
nextSlot := headBlock.GetPhase0Block().Block.Slot + 1
wsb, err := blocks.NewSignedBeaconBlock(headBlock.Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block)
b := util.NewBeaconBlock()
blk, err := blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
mockChainService := &mock.ChainService{
DB: beaconDB,
Block: wsb,
Root: headBlock.BlockRoot,
FinalizedCheckPoint: &ethpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot},
CanonicalRoots: canonicalRoots,
FinalizedRoots: map[[32]byte]bool{},
}
bs := &Server{
BeaconDB: beaconDB,
ChainInfoFetcher: mockChainService,
HeadFetcher: mockChainService,
OptimisticModeFetcher: mockChainService,
FinalizationFetcher: mockChainService,
FinalizationFetcher: &mock.ChainService{},
Blocker: &testutil.MockBlocker{BlockToReturn: blk},
}
root, err := genBlk.Block.HashTreeRoot()
expected, err := migration.V1Alpha1ToV1SignedBlock(b)
require.NoError(t, err)
tests := []struct {
name string
blockID []byte
want *ethpbalpha.SignedBeaconBlock
wantErr bool
}{
{
name: "slot",
blockID: []byte("30"),
want: blkContainers[30].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block,
},
{
name: "bad formatting",
blockID: []byte("3bad0"),
wantErr: true,
},
{
name: "canonical",
blockID: []byte("30"),
want: blkContainers[30].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block,
},
{
name: "non canonical",
blockID: []byte(fmt.Sprintf("%d", nextSlot)),
wantErr: true,
},
{
name: "head",
blockID: []byte("head"),
want: headBlock.Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block,
},
{
name: "finalized",
blockID: []byte("finalized"),
want: blkContainers[64].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block,
},
{
name: "genesis",
blockID: []byte("genesis"),
want: genBlk,
},
{
name: "genesis root",
blockID: root[:],
want: genBlk,
},
{
name: "root",
blockID: blkContainers[20].BlockRoot,
want: blkContainers[20].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block,
},
{
name: "non-existent root",
blockID: bytesutil.PadTo([]byte("hi there"), 32),
wantErr: true,
},
{
name: "no block",
blockID: []byte("105"),
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
blk, err := bs.GetBlindedBlock(ctx, &ethpbv1.BlockRequest{
BlockId: tt.blockID,
})
if tt.wantErr {
require.NotEqual(t, err, nil)
return
}
require.NoError(t, err)
v1Block, err := migration.V1Alpha1ToV1SignedBlock(tt.want)
require.NoError(t, err)
phase0Block, ok := blk.Data.Message.(*ethpbv2.SignedBlindedBeaconBlockContainer_Phase0Block)
require.Equal(t, true, ok)
if !reflect.DeepEqual(phase0Block.Phase0Block, v1Block.Block) {
t.Error("Expected blocks to equal")
}
assert.Equal(t, ethpbv2.Version_PHASE0, blk.Version)
})
}
resp, err := bs.GetBlindedBlock(ctx, &ethpbv1.BlockRequest{})
require.NoError(t, err)
phase0Block, ok := resp.Data.Message.(*ethpbv2.SignedBlindedBeaconBlockContainer_Phase0Block)
require.Equal(t, true, ok)
assert.DeepEqual(t, expected.Block, phase0Block.Phase0Block)
assert.Equal(t, ethpbv2.Version_PHASE0, resp.Version)
})
t.Run("Altair", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
genBlk, blkContainers := fillDBTestBlocksAltair(ctx, t, beaconDB)
canonicalRoots := make(map[[32]byte]bool)
for _, bContr := range blkContainers {
canonicalRoots[bytesutil.ToBytes32(bContr.BlockRoot)] = true
}
headBlock := blkContainers[len(blkContainers)-1]
nextSlot := headBlock.GetAltairBlock().Block.Slot + 1
chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetAltairBlock())
b := util.NewBeaconBlockAltair()
blk, err := blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
mockChainService := &mock.ChainService{
DB: beaconDB,
Block: chainBlk,
Root: headBlock.BlockRoot,
FinalizedCheckPoint: &ethpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot},
CanonicalRoots: canonicalRoots,
FinalizedRoots: map[[32]byte]bool{},
}
bs := &Server{
BeaconDB: beaconDB,
ChainInfoFetcher: mockChainService,
HeadFetcher: mockChainService,
OptimisticModeFetcher: mockChainService,
FinalizationFetcher: mockChainService,
FinalizationFetcher: &mock.ChainService{},
Blocker: &testutil.MockBlocker{BlockToReturn: blk},
}
root, err := genBlk.Block.HashTreeRoot()
expected, err := migration.V1Alpha1BeaconBlockAltairToV2(b.Block)
require.NoError(t, err)
tests := []struct {
name string
blockID []byte
want *ethpbalpha.SignedBeaconBlockAltair
wantErr bool
}{
{
name: "slot",
blockID: []byte("30"),
want: blkContainers[30].GetAltairBlock(),
},
{
name: "bad formatting",
blockID: []byte("3bad0"),
wantErr: true,
},
{
name: "canonical",
blockID: []byte("30"),
want: blkContainers[30].GetAltairBlock(),
},
{
name: "non canonical",
blockID: []byte(fmt.Sprintf("%d", nextSlot)),
wantErr: true,
},
{
name: "head",
blockID: []byte("head"),
want: headBlock.GetAltairBlock(),
},
{
name: "finalized",
blockID: []byte("finalized"),
want: blkContainers[64].GetAltairBlock(),
},
{
name: "genesis",
blockID: []byte("genesis"),
want: genBlk,
},
{
name: "genesis root",
blockID: root[:],
want: genBlk,
},
{
name: "root",
blockID: blkContainers[20].BlockRoot,
want: blkContainers[20].GetAltairBlock(),
},
{
name: "non-existent root",
blockID: bytesutil.PadTo([]byte("hi there"), 32),
wantErr: true,
},
{
name: "no block",
blockID: []byte("105"),
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
blk, err := bs.GetBlindedBlock(ctx, &ethpbv1.BlockRequest{
BlockId: tt.blockID,
})
if tt.wantErr {
require.NotEqual(t, err, nil)
return
}
require.NoError(t, err)
v2Block, err := migration.V1Alpha1BeaconBlockAltairToV2(tt.want.Block)
require.NoError(t, err)
altairBlock, ok := blk.Data.Message.(*ethpbv2.SignedBlindedBeaconBlockContainer_AltairBlock)
require.Equal(t, true, ok)
if !reflect.DeepEqual(altairBlock.AltairBlock, v2Block) {
t.Error("Expected blocks to equal")
}
assert.Equal(t, ethpbv2.Version_ALTAIR, blk.Version)
})
}
resp, err := bs.GetBlindedBlock(ctx, &ethpbv1.BlockRequest{})
require.NoError(t, err)
altairBlock, ok := resp.Data.Message.(*ethpbv2.SignedBlindedBeaconBlockContainer_AltairBlock)
require.Equal(t, true, ok)
assert.DeepEqual(t, expected, altairBlock.AltairBlock)
assert.Equal(t, ethpbv2.Version_ALTAIR, resp.Version)
})
t.Run("Bellatrix", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
genBlk, blkContainers := fillDBTestBlocksBellatrixBlinded(ctx, t, beaconDB)
canonicalRoots := make(map[[32]byte]bool)
for _, bContr := range blkContainers {
canonicalRoots[bytesutil.ToBytes32(bContr.BlockRoot)] = true
}
headBlock := blkContainers[len(blkContainers)-1]
nextSlot := headBlock.GetBlindedBellatrixBlock().Block.Slot + 1
chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetBlindedBellatrixBlock())
b := util.NewBlindedBeaconBlockBellatrix()
blk, err := blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
mockChainService := &mock.ChainService{
DB: beaconDB,
Block: chainBlk,
Root: headBlock.BlockRoot,
FinalizedCheckPoint: &ethpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot},
CanonicalRoots: canonicalRoots,
FinalizedRoots: map[[32]byte]bool{},
}
mockChainService := &mock.ChainService{}
bs := &Server{
BeaconDB: beaconDB,
ChainInfoFetcher: mockChainService,
HeadFetcher: mockChainService,
FinalizationFetcher: mockChainService,
Blocker: &testutil.MockBlocker{BlockToReturn: blk},
OptimisticModeFetcher: mockChainService,
ExecutionPayloadReconstructor: &executionTest.EngineClient{
ExecutionPayloadByBlockHash: map[[32]byte]*enginev1.ExecutionPayload{},
},
FinalizationFetcher: mockChainService,
}
root, err := genBlk.Block.HashTreeRoot()
expected, err := migration.V1Alpha1BeaconBlockBlindedBellatrixToV2Blinded(b.Block)
require.NoError(t, err)
tests := []struct {
name string
blockID []byte
want *ethpbalpha.SignedBlindedBeaconBlockBellatrix
wantErr bool
}{
{
name: "slot",
blockID: []byte("30"),
want: blkContainers[30].GetBlindedBellatrixBlock(),
},
{
name: "bad formatting",
blockID: []byte("3bad0"),
wantErr: true,
},
{
name: "canonical",
blockID: []byte("30"),
want: blkContainers[30].GetBlindedBellatrixBlock(),
},
{
name: "non canonical",
blockID: []byte(fmt.Sprintf("%d", nextSlot)),
wantErr: true,
},
{
name: "head",
blockID: []byte("head"),
want: headBlock.GetBlindedBellatrixBlock(),
},
{
name: "finalized",
blockID: []byte("finalized"),
want: blkContainers[64].GetBlindedBellatrixBlock(),
},
{
name: "genesis",
blockID: []byte("genesis"),
want: genBlk,
},
{
name: "genesis root",
blockID: root[:],
want: genBlk,
},
{
name: "root",
blockID: blkContainers[20].BlockRoot,
want: blkContainers[20].GetBlindedBellatrixBlock(),
},
{
name: "non-existent root",
blockID: bytesutil.PadTo([]byte("hi there"), 32),
wantErr: true,
},
{
name: "no block",
blockID: []byte("105"),
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
blk, err := bs.GetBlindedBlock(ctx, &ethpbv1.BlockRequest{
BlockId: tt.blockID,
})
if tt.wantErr {
require.NotEqual(t, err, nil)
return
}
require.NoError(t, err)
v2Block, err := migration.V1Alpha1BeaconBlockBlindedBellatrixToV2Blinded(tt.want.Block)
require.NoError(t, err)
b, ok := blk.Data.Message.(*ethpbv2.SignedBlindedBeaconBlockContainer_BellatrixBlock)
require.Equal(t, true, ok)
if !reflect.DeepEqual(b.BellatrixBlock, v2Block) {
t.Error("Expected blocks to equal")
}
assert.Equal(t, ethpbv2.Version_BELLATRIX, blk.Version)
})
}
resp, err := bs.GetBlindedBlock(ctx, &ethpbv1.BlockRequest{})
require.NoError(t, err)
bellatrixBlock, ok := resp.Data.Message.(*ethpbv2.SignedBlindedBeaconBlockContainer_BellatrixBlock)
require.Equal(t, true, ok)
assert.DeepEqual(t, expected, bellatrixBlock.BellatrixBlock)
assert.Equal(t, ethpbv2.Version_BELLATRIX, resp.Version)
})
t.Run("Capella", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
genBlk, blkContainers := fillDBTestBlocksCapellaBlinded(ctx, t, beaconDB)
canonicalRoots := make(map[[32]byte]bool)
for _, bContr := range blkContainers {
canonicalRoots[bytesutil.ToBytes32(bContr.BlockRoot)] = true
}
headBlock := blkContainers[len(blkContainers)-1]
nextSlot := headBlock.GetBlindedCapellaBlock().Block.Slot + 1
chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetBlindedCapellaBlock())
b := util.NewBlindedBeaconBlockCapella()
blk, err := blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
mockChainService := &mock.ChainService{
DB: beaconDB,
Block: chainBlk,
Root: headBlock.BlockRoot,
FinalizedCheckPoint: &ethpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot},
CanonicalRoots: canonicalRoots,
FinalizedRoots: map[[32]byte]bool{},
}
mockChainService := &mock.ChainService{}
bs := &Server{
BeaconDB: beaconDB,
ChainInfoFetcher: mockChainService,
HeadFetcher: mockChainService,
FinalizationFetcher: mockChainService,
Blocker: &testutil.MockBlocker{BlockToReturn: blk},
OptimisticModeFetcher: mockChainService,
ExecutionPayloadReconstructor: &executionTest.EngineClient{
ExecutionPayloadByBlockHash: map[[32]byte]*enginev1.ExecutionPayload{},
},
FinalizationFetcher: mockChainService,
}
root, err := genBlk.Block.HashTreeRoot()
expected, err := migration.V1Alpha1BeaconBlockBlindedCapellaToV2Blinded(b.Block)
require.NoError(t, err)
tests := []struct {
name string
blockID []byte
want *ethpbalpha.SignedBlindedBeaconBlockCapella
wantErr bool
}{
{
name: "slot",
blockID: []byte("30"),
want: blkContainers[30].GetBlindedCapellaBlock(),
},
{
name: "bad formatting",
blockID: []byte("3bad0"),
wantErr: true,
},
{
name: "canonical",
blockID: []byte("30"),
want: blkContainers[30].GetBlindedCapellaBlock(),
},
{
name: "non canonical",
blockID: []byte(fmt.Sprintf("%d", nextSlot)),
wantErr: true,
},
{
name: "head",
blockID: []byte("head"),
want: headBlock.GetBlindedCapellaBlock(),
},
{
name: "finalized",
blockID: []byte("finalized"),
want: blkContainers[64].GetBlindedCapellaBlock(),
},
{
name: "genesis",
blockID: []byte("genesis"),
want: genBlk,
},
{
name: "genesis root",
blockID: root[:],
want: genBlk,
},
{
name: "root",
blockID: blkContainers[20].BlockRoot,
want: blkContainers[20].GetBlindedCapellaBlock(),
},
{
name: "non-existent root",
blockID: bytesutil.PadTo([]byte("hi there"), 32),
wantErr: true,
},
{
name: "no block",
blockID: []byte("105"),
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
blk, err := bs.GetBlindedBlock(ctx, &ethpbv1.BlockRequest{
BlockId: tt.blockID,
})
if tt.wantErr {
require.NotEqual(t, err, nil)
return
}
require.NoError(t, err)
v2Block, err := migration.V1Alpha1BeaconBlockBlindedCapellaToV2Blinded(tt.want.Block)
require.NoError(t, err)
b, ok := blk.Data.Message.(*ethpbv2.SignedBlindedBeaconBlockContainer_CapellaBlock)
require.Equal(t, true, ok)
if !reflect.DeepEqual(b.CapellaBlock, v2Block) {
t.Error("Expected blocks to equal")
}
assert.Equal(t, ethpbv2.Version_CAPELLA, blk.Version)
})
}
resp, err := bs.GetBlindedBlock(ctx, &ethpbv1.BlockRequest{})
require.NoError(t, err)
capellaBlock, ok := resp.Data.Message.(*ethpbv2.SignedBlindedBeaconBlockContainer_CapellaBlock)
require.Equal(t, true, ok)
assert.DeepEqual(t, expected, capellaBlock.CapellaBlock)
assert.Equal(t, ethpbv2.Version_CAPELLA, resp.Version)
})
t.Run("execution optimistic", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
_, blkContainers := fillDBTestBlocksBellatrix(ctx, t, beaconDB)
headBlock := blkContainers[len(blkContainers)-1]
chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetBellatrixBlock())
b := util.NewBlindedBeaconBlockBellatrix()
blk, err := blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
r, err := blk.Block().HashTreeRoot()
require.NoError(t, err)
mockChainService := &mock.ChainService{
DB: beaconDB,
Block: chainBlk,
Root: headBlock.BlockRoot,
FinalizedCheckPoint: &ethpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot},
Optimistic: true,
FinalizedRoots: map[[32]byte]bool{},
OptimisticRoots: map[[32]byte]bool{r: true},
}
bs := &Server{
BeaconDB: beaconDB,
ChainInfoFetcher: mockChainService,
HeadFetcher: mockChainService,
OptimisticModeFetcher: mockChainService,
FinalizationFetcher: mockChainService,
Blocker: &testutil.MockBlocker{BlockToReturn: blk},
OptimisticModeFetcher: mockChainService,
}
blk, err := bs.GetBlindedBlock(ctx, &ethpbv1.BlockRequest{
BlockId: []byte("head"),
})
resp, err := bs.GetBlindedBlock(ctx, &ethpbv1.BlockRequest{})
require.NoError(t, err)
assert.Equal(t, true, blk.ExecutionOptimistic)
assert.Equal(t, true, resp.ExecutionOptimistic)
})
t.Run("finalized", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
_, blkContainers := fillDBTestBlocks(ctx, t, beaconDB)
headBlock := blkContainers[len(blkContainers)-1]
chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetPhase0Block())
b := util.NewBeaconBlock()
blk, err := blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
root, err := blk.Block().HashTreeRoot()
require.NoError(t, err)
mockChainService := &mock.ChainService{
DB: beaconDB,
Block: chainBlk,
Root: headBlock.BlockRoot,
FinalizedCheckPoint: &ethpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot},
Optimistic: true,
FinalizedRoots: map[[32]byte]bool{
bytesutil.ToBytes32(blkContainers[32].BlockRoot): true,
bytesutil.ToBytes32(blkContainers[64].BlockRoot): false,
},
FinalizedRoots: map[[32]byte]bool{root: true},
}
bs := &Server{
BeaconDB: beaconDB,
ChainInfoFetcher: mockChainService,
HeadFetcher: mockChainService,
OptimisticModeFetcher: mockChainService,
FinalizationFetcher: mockChainService,
FinalizationFetcher: mockChainService,
Blocker: &testutil.MockBlocker{BlockToReturn: blk},
}
t.Run("true", func(t *testing.T) {
blk, err := bs.GetBlindedBlock(ctx, &ethpbv1.BlockRequest{
BlockId: []byte("32"),
})
require.NoError(t, err)
assert.Equal(t, true, blk.Finalized)
})
t.Run("false", func(t *testing.T) {
blk, err := bs.GetBlindedBlock(ctx, &ethpbv1.BlockRequest{
BlockId: []byte("64"),
})
require.NoError(t, err)
assert.Equal(t, false, blk.Finalized)
})
resp, err := bs.GetBlindedBlock(ctx, &ethpbv1.BlockRequest{BlockId: root[:]})
require.NoError(t, err)
assert.Equal(t, true, resp.Finalized)
})
t.Run("not finalized", func(t *testing.T) {
b := util.NewBeaconBlock()
blk, err := blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
root, err := blk.Block().HashTreeRoot()
require.NoError(t, err)
mockChainService := &mock.ChainService{
FinalizedRoots: map[[32]byte]bool{root: false},
}
bs := &Server{
FinalizationFetcher: mockChainService,
Blocker: &testutil.MockBlocker{BlockToReturn: blk},
}
resp, err := bs.GetBlindedBlock(ctx, &ethpbv1.BlockRequest{BlockId: root[:]})
require.NoError(t, err)
assert.Equal(t, false, resp.Finalized)
})
}
func TestServer_GetBlindedBlockSSZ(t *testing.T) {
ctx := context.Background()
t.Run("Phase 0", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
_, blkContainers := fillDBTestBlocks(ctx, t, beaconDB)
headBlock := blkContainers[len(blkContainers)-1]
wsb, err := blocks.NewSignedBeaconBlock(headBlock.Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block)
b := util.NewBeaconBlock()
blk, err := blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
mockChainService := &mock.ChainService{
DB: beaconDB,
Block: wsb,
Root: headBlock.BlockRoot,
FinalizedCheckPoint: &ethpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot},
FinalizedRoots: map[[32]byte]bool{},
}
bs := &Server{
BeaconDB: beaconDB,
ChainInfoFetcher: mockChainService,
FinalizationFetcher: mockChainService,
FinalizationFetcher: &mock.ChainService{},
Blocker: &testutil.MockBlocker{BlockToReturn: blk},
}
blks, err := beaconDB.BlocksBySlot(ctx, 30)
require.Equal(t, true, len(blks) > 0)
expected, err := blk.MarshalSSZ()
require.NoError(t, err)
sszBlock, err := blks[0].MarshalSSZ()
require.NoError(t, err)
resp, err := bs.GetBlindedBlockSSZ(ctx, &ethpbv1.BlockRequest{BlockId: []byte("30")})
resp, err := bs.GetBlindedBlockSSZ(ctx, &ethpbv1.BlockRequest{})
require.NoError(t, err)
assert.NotNil(t, resp)
assert.DeepEqual(t, sszBlock, resp.Data)
assert.DeepEqual(t, expected, resp.Data)
assert.Equal(t, ethpbv2.Version_PHASE0, resp.Version)
})
t.Run("Altair", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
_, blkContainers := fillDBTestBlocksAltair(ctx, t, beaconDB)
headBlock := blkContainers[len(blkContainers)-1]
chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetAltairBlock())
b := util.NewBeaconBlockAltair()
blk, err := blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
mockChainService := &mock.ChainService{
DB: beaconDB,
Block: chainBlk,
Root: headBlock.BlockRoot,
FinalizedCheckPoint: &ethpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot},
FinalizedRoots: map[[32]byte]bool{},
}
bs := &Server{
BeaconDB: beaconDB,
ChainInfoFetcher: mockChainService,
FinalizationFetcher: mockChainService,
FinalizationFetcher: &mock.ChainService{},
Blocker: &testutil.MockBlocker{BlockToReturn: blk},
}
blks, err := beaconDB.BlocksBySlot(ctx, 30)
require.Equal(t, true, len(blks) > 0)
expected, err := blk.MarshalSSZ()
require.NoError(t, err)
sszBlock, err := blks[0].MarshalSSZ()
require.NoError(t, err)
resp, err := bs.GetBlindedBlockSSZ(ctx, &ethpbv1.BlockRequest{BlockId: []byte("30")})
resp, err := bs.GetBlindedBlockSSZ(ctx, &ethpbv1.BlockRequest{})
require.NoError(t, err)
assert.NotNil(t, resp)
assert.DeepEqual(t, sszBlock, resp.Data)
assert.DeepEqual(t, expected, resp.Data)
assert.Equal(t, ethpbv2.Version_ALTAIR, resp.Version)
})
t.Run("Bellatrix", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
_, blkContainers := fillDBTestBlocksBellatrixBlinded(ctx, t, beaconDB)
headBlock := blkContainers[len(blkContainers)-1]
chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetBlindedBellatrixBlock())
b := util.NewBlindedBeaconBlockBellatrix()
blk, err := blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
mockChainService := &mock.ChainService{
DB: beaconDB,
Block: chainBlk,
Root: headBlock.BlockRoot,
FinalizedCheckPoint: &ethpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot},
FinalizedRoots: map[[32]byte]bool{},
}
mockChainService := &mock.ChainService{}
bs := &Server{
BeaconDB: beaconDB,
ChainInfoFetcher: mockChainService,
OptimisticModeFetcher: mockChainService,
FinalizationFetcher: mockChainService,
Blocker: &testutil.MockBlocker{BlockToReturn: blk},
OptimisticModeFetcher: mockChainService,
}
blks, err := beaconDB.BlocksBySlot(ctx, 30)
require.Equal(t, true, len(blks) > 0)
expected, err := blk.MarshalSSZ()
require.NoError(t, err)
sszBlock, err := blks[0].MarshalSSZ()
require.NoError(t, err)
resp, err := bs.GetBlindedBlockSSZ(ctx, &ethpbv1.BlockRequest{BlockId: []byte("30")})
resp, err := bs.GetBlindedBlockSSZ(ctx, &ethpbv1.BlockRequest{})
require.NoError(t, err)
assert.NotNil(t, resp)
assert.DeepEqual(t, sszBlock, resp.Data)
assert.DeepEqual(t, expected, resp.Data)
assert.Equal(t, ethpbv2.Version_BELLATRIX, resp.Version)
})
t.Run("Capella", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
_, blkContainers := fillDBTestBlocksCapellaBlinded(ctx, t, beaconDB)
headBlock := blkContainers[len(blkContainers)-1]
chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetBlindedCapellaBlock())
b := util.NewBlindedBeaconBlockCapella()
blk, err := blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
mockChainService := &mock.ChainService{
DB: beaconDB,
Block: chainBlk,
Root: headBlock.BlockRoot,
FinalizedCheckPoint: &ethpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot},
FinalizedRoots: map[[32]byte]bool{},
}
mockChainService := &mock.ChainService{}
bs := &Server{
BeaconDB: beaconDB,
ChainInfoFetcher: mockChainService,
OptimisticModeFetcher: mockChainService,
FinalizationFetcher: mockChainService,
Blocker: &testutil.MockBlocker{BlockToReturn: blk},
OptimisticModeFetcher: mockChainService,
}
blks, err := beaconDB.BlocksBySlot(ctx, 30)
require.Equal(t, true, len(blks) > 0)
expected, err := blk.MarshalSSZ()
require.NoError(t, err)
sszBlock, err := blks[0].MarshalSSZ()
require.NoError(t, err)
resp, err := bs.GetBlindedBlockSSZ(ctx, &ethpbv1.BlockRequest{BlockId: []byte("30")})
resp, err := bs.GetBlindedBlockSSZ(ctx, &ethpbv1.BlockRequest{})
require.NoError(t, err)
assert.NotNil(t, resp)
assert.DeepEqual(t, sszBlock, resp.Data)
assert.DeepEqual(t, expected, resp.Data)
assert.Equal(t, ethpbv2.Version_CAPELLA, resp.Version)
})
t.Run("execution optimistic", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
_, blkContainers := fillDBTestBlocksBellatrix(ctx, t, beaconDB)
headBlock := blkContainers[len(blkContainers)-1]
chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetBellatrixBlock())
b := util.NewBlindedBeaconBlockBellatrix()
blk, err := blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
r, err := blk.Block().HashTreeRoot()
require.NoError(t, err)
mockChainService := &mock.ChainService{
DB: beaconDB,
Block: chainBlk,
Root: headBlock.BlockRoot,
FinalizedCheckPoint: &ethpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot},
Optimistic: true,
FinalizedRoots: map[[32]byte]bool{},
OptimisticRoots: map[[32]byte]bool{r: true},
}
bs := &Server{
BeaconDB: beaconDB,
ChainInfoFetcher: mockChainService,
HeadFetcher: mockChainService,
OptimisticModeFetcher: mockChainService,
FinalizationFetcher: mockChainService,
Blocker: &testutil.MockBlocker{BlockToReturn: blk},
OptimisticModeFetcher: mockChainService,
}
blk, err := bs.GetBlindedBlockSSZ(ctx, &ethpbv1.BlockRequest{
BlockId: []byte("head"),
})
resp, err := bs.GetBlindedBlockSSZ(ctx, &ethpbv1.BlockRequest{})
require.NoError(t, err)
assert.Equal(t, true, blk.ExecutionOptimistic)
assert.Equal(t, true, resp.ExecutionOptimistic)
})
t.Run("finalized", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
_, blkContainers := fillDBTestBlocks(ctx, t, beaconDB)
headBlock := blkContainers[len(blkContainers)-1]
chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetPhase0Block())
b := util.NewBeaconBlock()
blk, err := blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
root, err := blk.Block().HashTreeRoot()
require.NoError(t, err)
mockChainService := &mock.ChainService{
DB: beaconDB,
Block: chainBlk,
Root: headBlock.BlockRoot,
FinalizedCheckPoint: &ethpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot},
Optimistic: true,
FinalizedRoots: map[[32]byte]bool{
bytesutil.ToBytes32(blkContainers[32].BlockRoot): true,
bytesutil.ToBytes32(blkContainers[64].BlockRoot): false,
},
FinalizedRoots: map[[32]byte]bool{root: true},
}
bs := &Server{
BeaconDB: beaconDB,
ChainInfoFetcher: mockChainService,
HeadFetcher: mockChainService,
OptimisticModeFetcher: mockChainService,
FinalizationFetcher: mockChainService,
FinalizationFetcher: mockChainService,
Blocker: &testutil.MockBlocker{BlockToReturn: blk},
}
t.Run("true", func(t *testing.T) {
blk, err := bs.GetBlindedBlockSSZ(ctx, &ethpbv1.BlockRequest{
BlockId: []byte("32"),
})
require.NoError(t, err)
assert.Equal(t, true, blk.Finalized)
})
t.Run("false", func(t *testing.T) {
blk, err := bs.GetBlindedBlockSSZ(ctx, &ethpbv1.BlockRequest{
BlockId: []byte("64"),
})
require.NoError(t, err)
assert.Equal(t, false, blk.Finalized)
})
resp, err := bs.GetBlindedBlockSSZ(ctx, &ethpbv1.BlockRequest{BlockId: root[:]})
require.NoError(t, err)
assert.Equal(t, true, resp.Finalized)
})
t.Run("not finalized", func(t *testing.T) {
b := util.NewBeaconBlock()
blk, err := blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
root, err := blk.Block().HashTreeRoot()
require.NoError(t, err)
mockChainService := &mock.ChainService{
FinalizedRoots: map[[32]byte]bool{root: false},
}
bs := &Server{
FinalizationFetcher: mockChainService,
Blocker: &testutil.MockBlocker{BlockToReturn: blk},
}
resp, err := bs.GetBlindedBlockSSZ(ctx, &ethpbv1.BlockRequest{BlockId: root[:]})
require.NoError(t, err)
assert.Equal(t, false, resp.Finalized)
})
}
@@ -878,14 +389,6 @@ func TestServer_SubmitBlindedBlockSSZ_OK(t *testing.T) {
})
t.Run("Bellatrix", func(t *testing.T) {
// INFO: This code block can be removed once Bellatrix
// fork epoch is set to a value other than math.MaxUint64
params.SetupTestConfigCleanup(t)
cfg := params.BeaconConfig()
cfg.BellatrixForkEpoch = cfg.AltairForkEpoch + 1000
cfg.ForkVersionSchedule[bytesutil.ToBytes4(cfg.BellatrixForkVersion)] = cfg.AltairForkEpoch + 1000
params.OverrideBeaconConfig(cfg)
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
@@ -934,16 +437,6 @@ func TestServer_SubmitBlindedBlockSSZ_OK(t *testing.T) {
})
t.Run("Capella", func(t *testing.T) {
t.Skip("This test needs Capella fork version configured properly")
// INFO: This code block can be removed once Capella
// fork epoch is set to a value other than math.MaxUint64
params.SetupTestConfigCleanup(t)
cfg := params.BeaconConfig()
cfg.CapellaForkEpoch = cfg.BellatrixForkEpoch + 1000
cfg.ForkVersionSchedule[bytesutil.ToBytes4(cfg.CapellaForkVersion)] = cfg.BellatrixForkEpoch + 1000
params.OverrideBeaconConfig(cfg)
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()

View File

@@ -12,6 +12,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/db/filters"
rpchelpers "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/helpers"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup"
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
"github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
@@ -37,23 +38,6 @@ var (
errNilBlock = errors.New("nil block")
)
// blockIdParseError represents an error scenario where a block ID could not be parsed.
type blockIdParseError struct {
message string
}
// newBlockIdParseError creates a new error instance.
func newBlockIdParseError(reason error) blockIdParseError {
return blockIdParseError{
message: errors.Wrapf(reason, "could not parse block ID").Error(),
}
}
// Error returns the underlying error message.
func (e *blockIdParseError) Error() string {
return e.message
}
// GetWeakSubjectivity computes the starting epoch of the current weak subjectivity period, and then also
// determines the best block root and state root to use for a Checkpoint Sync starting from that point.
// DEPRECATED: GetWeakSubjectivity endpoint will no longer be supported
@@ -101,7 +85,7 @@ func (bs *Server) GetBlockHeader(ctx context.Context, req *ethpbv1.BlockRequest)
ctx, span := trace.StartSpan(ctx, "beacon.GetBlockHeader")
defer span.End()
blk, err := bs.blockFromBlockID(ctx, req.BlockId)
blk, err := bs.Blocker.Block(ctx, req.BlockId)
err = handleGetBlockError(blk, err)
if err != nil {
return nil, err
@@ -290,7 +274,7 @@ func (bs *Server) GetBlock(ctx context.Context, req *ethpbv1.BlockRequest) (*eth
ctx, span := trace.StartSpan(ctx, "beacon.GetBlock")
defer span.End()
blk, err := bs.blockFromBlockID(ctx, req.BlockId)
blk, err := bs.Blocker.Block(ctx, req.BlockId)
err = handleGetBlockError(blk, err)
if err != nil {
return nil, err
@@ -314,7 +298,7 @@ func (bs *Server) GetBlockSSZ(ctx context.Context, req *ethpbv1.BlockRequest) (*
ctx, span := trace.StartSpan(ctx, "beacon.GetBlockSSZ")
defer span.End()
blk, err := bs.blockFromBlockID(ctx, req.BlockId)
blk, err := bs.Blocker.Block(ctx, req.BlockId)
err = handleGetBlockError(blk, err)
if err != nil {
return nil, err
@@ -336,7 +320,7 @@ func (bs *Server) GetBlockV2(ctx context.Context, req *ethpbv2.BlockRequestV2) (
ctx, span := trace.StartSpan(ctx, "beacon.GetBlockV2")
defer span.End()
blk, err := bs.blockFromBlockID(ctx, req.BlockId)
blk, err := bs.Blocker.Block(ctx, req.BlockId)
err = handleGetBlockError(blk, err)
if err != nil {
return nil, err
@@ -390,7 +374,7 @@ func (bs *Server) GetBlockSSZV2(ctx context.Context, req *ethpbv2.BlockRequestV2
ctx, span := trace.StartSpan(ctx, "beacon.GetBlockSSZV2")
defer span.End()
blk, err := bs.blockFromBlockID(ctx, req.BlockId)
blk, err := bs.Blocker.Block(ctx, req.BlockId)
err = handleGetBlockError(blk, err)
if err != nil {
return nil, err
@@ -532,7 +516,7 @@ func (bs *Server) ListBlockAttestations(ctx context.Context, req *ethpbv1.BlockR
ctx, span := trace.StartSpan(ctx, "beacon.ListBlockAttestations")
defer span.End()
blk, err := bs.blockFromBlockID(ctx, req.BlockId)
blk, err := bs.Blocker.Block(ctx, req.BlockId)
err = handleGetBlockError(blk, err)
if err != nil {
return nil, err
@@ -559,68 +543,8 @@ func (bs *Server) ListBlockAttestations(ctx context.Context, req *ethpbv1.BlockR
}, nil
}
func (bs *Server) blockFromBlockID(ctx context.Context, blockId []byte) (interfaces.ReadOnlySignedBeaconBlock, error) {
var err error
var blk interfaces.ReadOnlySignedBeaconBlock
switch string(blockId) {
case "head":
blk, err = bs.ChainInfoFetcher.HeadBlock(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not retrieve head block")
}
case "finalized":
finalized := bs.ChainInfoFetcher.FinalizedCheckpt()
finalizedRoot := bytesutil.ToBytes32(finalized.Root)
blk, err = bs.BeaconDB.Block(ctx, finalizedRoot)
if err != nil {
return nil, errors.New("could not get finalized block from db")
}
case "genesis":
blk, err = bs.BeaconDB.GenesisBlock(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not retrieve blocks for genesis slot")
}
default:
if len(blockId) == 32 {
blk, err = bs.BeaconDB.Block(ctx, bytesutil.ToBytes32(blockId))
if err != nil {
return nil, errors.Wrap(err, "could not retrieve block")
}
} else {
slot, err := strconv.ParseUint(string(blockId), 10, 64)
if err != nil {
e := newBlockIdParseError(err)
return nil, &e
}
blks, err := bs.BeaconDB.BlocksBySlot(ctx, primitives.Slot(slot))
if err != nil {
return nil, errors.Wrapf(err, "could not retrieve blocks for slot %d", slot)
}
_, roots, err := bs.BeaconDB.BlockRootsBySlot(ctx, primitives.Slot(slot))
if err != nil {
return nil, errors.Wrapf(err, "could not retrieve block roots for slot %d", slot)
}
numBlks := len(blks)
if numBlks == 0 {
return nil, nil
}
for i, b := range blks {
canonical, err := bs.ChainInfoFetcher.IsCanonical(ctx, roots[i])
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not determine if block root is canonical: %v", err)
}
if canonical {
blk = b
break
}
}
}
}
return blk, nil
}
func handleGetBlockError(blk interfaces.ReadOnlySignedBeaconBlock, err error) error {
if invalidBlockIdErr, ok := err.(*blockIdParseError); ok {
if invalidBlockIdErr, ok := err.(*lookup.BlockIdParseError); ok {
return status.Errorf(codes.InvalidArgument, "Invalid block ID: %v", invalidBlockIdErr)
}
if err != nil {

File diff suppressed because it is too large Load Diff

View File

@@ -186,7 +186,7 @@ func (bs *Server) SubmitAttesterSlashing(ctx context.Context, req *ethpbv1.Attes
return nil, status.Errorf(codes.Internal, "Could not insert attester slashing into pool: %v", err)
}
if !features.Get().DisableBroadcastSlashings {
if err := bs.Broadcaster.Broadcast(ctx, req); err != nil {
if err := bs.Broadcaster.Broadcast(ctx, alphaSlashing); err != nil {
return nil, status.Errorf(codes.Internal, "Could not broadcast slashing object: %v", err)
}
}
@@ -242,7 +242,7 @@ func (bs *Server) SubmitProposerSlashing(ctx context.Context, req *ethpbv1.Propo
return nil, status.Errorf(codes.Internal, "Could not insert proposer slashing into pool: %v", err)
}
if !features.Get().DisableBroadcastSlashings {
if err := bs.Broadcaster.Broadcast(ctx, req); err != nil {
if err := bs.Broadcaster.Broadcast(ctx, alphaSlashing); err != nil {
return nil, status.Errorf(codes.Internal, "Could not broadcast slashing object: %v", err)
}
}

View File

@@ -452,6 +452,9 @@ func TestSubmitAttesterSlashing_Ok(t *testing.T) {
require.Equal(t, 1, len(pendingSlashings))
assert.DeepEqual(t, migration.V1AttSlashingToV1Alpha1(slashing), pendingSlashings[0])
assert.Equal(t, true, broadcaster.BroadcastCalled)
require.Equal(t, 1, len(broadcaster.BroadcastMessages))
_, ok := broadcaster.BroadcastMessages[0].(*ethpbv1alpha1.AttesterSlashing)
assert.Equal(t, true, ok)
}
func TestSubmitAttesterSlashing_AcrossFork(t *testing.T) {
@@ -526,6 +529,9 @@ func TestSubmitAttesterSlashing_AcrossFork(t *testing.T) {
require.Equal(t, 1, len(pendingSlashings))
assert.DeepEqual(t, migration.V1AttSlashingToV1Alpha1(slashing), pendingSlashings[0])
assert.Equal(t, true, broadcaster.BroadcastCalled)
require.Equal(t, 1, len(broadcaster.BroadcastMessages))
_, ok := broadcaster.BroadcastMessages[0].(*ethpbv1alpha1.AttesterSlashing)
assert.Equal(t, true, ok)
}
func TestSubmitAttesterSlashing_InvalidSlashing(t *testing.T) {
@@ -633,6 +639,9 @@ func TestSubmitProposerSlashing_Ok(t *testing.T) {
require.Equal(t, 1, len(pendingSlashings))
assert.DeepEqual(t, migration.V1ProposerSlashingToV1Alpha1(slashing), pendingSlashings[0])
assert.Equal(t, true, broadcaster.BroadcastCalled)
require.Equal(t, 1, len(broadcaster.BroadcastMessages))
_, ok := broadcaster.BroadcastMessages[0].(*ethpbv1alpha1.ProposerSlashing)
assert.Equal(t, true, ok)
}
func TestSubmitProposerSlashing_AcrossFork(t *testing.T) {
@@ -695,6 +704,13 @@ func TestSubmitProposerSlashing_AcrossFork(t *testing.T) {
_, err = s.SubmitProposerSlashing(ctx, slashing)
require.NoError(t, err)
pendingSlashings := s.SlashingsPool.PendingProposerSlashings(ctx, bs, true)
require.Equal(t, 1, len(pendingSlashings))
assert.DeepEqual(t, migration.V1ProposerSlashingToV1Alpha1(slashing), pendingSlashings[0])
assert.Equal(t, true, broadcaster.BroadcastCalled)
require.Equal(t, 1, len(broadcaster.BroadcastMessages))
_, ok := broadcaster.BroadcastMessages[0].(*ethpbv1alpha1.ProposerSlashing)
assert.Equal(t, true, ok)
}
func TestSubmitProposerSlashing_InvalidSlashing(t *testing.T) {

View File

@@ -14,8 +14,8 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/slashings"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/voluntaryexits"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup"
v1alpha1validator "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/prysm/v1alpha1/validator"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/statefetcher"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/sync"
)
@@ -34,7 +34,8 @@ type Server struct {
SlashingsPool slashings.PoolManager
VoluntaryExitsPool voluntaryexits.PoolManager
StateGenService stategen.StateManager
StateFetcher statefetcher.Fetcher
Stater lookup.Stater
Blocker lookup.Blocker
HeadFetcher blockchain.HeadFetcher
OptimisticModeFetcher blockchain.OptimisticModeFetcher
V1Alpha1ValidatorServer *v1alpha1validator.Server

View File

@@ -6,7 +6,7 @@ import (
"strconv"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/helpers"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/statefetcher"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
"github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
@@ -58,20 +58,20 @@ func (bs *Server) GetStateRoot(ctx context.Context, req *ethpb.StateRequest) (*e
ctx, span := trace.StartSpan(ctx, "beacon.GetStateRoot")
defer span.End()
stateRoot, err := bs.StateFetcher.StateRoot(ctx, req.StateId)
stateRoot, err := bs.Stater.StateRoot(ctx, req.StateId)
if err != nil {
if rootNotFoundErr, ok := err.(*statefetcher.StateRootNotFoundError); ok {
if rootNotFoundErr, ok := err.(*lookup.StateRootNotFoundError); ok {
return nil, status.Errorf(codes.NotFound, "State root not found: %v", rootNotFoundErr)
} else if parseErr, ok := err.(*statefetcher.StateIdParseError); ok {
} else if parseErr, ok := err.(*lookup.StateIdParseError); ok {
return nil, status.Errorf(codes.InvalidArgument, "Invalid state ID: %v", parseErr)
}
return nil, status.Errorf(codes.Internal, "Could not get state root: %v", err)
}
st, err := bs.StateFetcher.State(ctx, req.StateId)
st, err := bs.Stater.State(ctx, req.StateId)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get state: %v", err)
}
isOptimistic, err := helpers.IsOptimistic(ctx, st, bs.OptimisticModeFetcher)
isOptimistic, err := helpers.IsOptimistic(ctx, req.StateId, bs.OptimisticModeFetcher, bs.Stater, bs.ChainInfoFetcher, bs.BeaconDB)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not check if slot's block is optimistic: %v", err)
}
@@ -95,12 +95,12 @@ func (bs *Server) GetStateFork(ctx context.Context, req *ethpb.StateRequest) (*e
ctx, span := trace.StartSpan(ctx, "beacon.GetStateFork")
defer span.End()
st, err := bs.StateFetcher.State(ctx, req.StateId)
st, err := bs.Stater.State(ctx, req.StateId)
if err != nil {
return nil, helpers.PrepareStateFetchGRPCError(err)
}
fork := st.Fork()
isOptimistic, err := helpers.IsOptimistic(ctx, st, bs.OptimisticModeFetcher)
isOptimistic, err := helpers.IsOptimistic(ctx, req.StateId, bs.OptimisticModeFetcher, bs.Stater, bs.ChainInfoFetcher, bs.BeaconDB)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not check if slot's block is optimistic: %v", err)
}
@@ -127,11 +127,11 @@ func (bs *Server) GetFinalityCheckpoints(ctx context.Context, req *ethpb.StateRe
ctx, span := trace.StartSpan(ctx, "beacon.GetFinalityCheckpoints")
defer span.End()
st, err := bs.StateFetcher.State(ctx, req.StateId)
st, err := bs.Stater.State(ctx, req.StateId)
if err != nil {
return nil, helpers.PrepareStateFetchGRPCError(err)
}
isOptimistic, err := helpers.IsOptimistic(ctx, st, bs.OptimisticModeFetcher)
isOptimistic, err := helpers.IsOptimistic(ctx, req.StateId, bs.OptimisticModeFetcher, bs.Stater, bs.ChainInfoFetcher, bs.BeaconDB)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not check if slot's block is optimistic: %v", err)
}
@@ -160,7 +160,7 @@ func (bs *Server) GetRandao(ctx context.Context, req *eth2.RandaoRequest) (*eth2
ctx, span := trace.StartSpan(ctx, "beacon.GetRandao")
defer span.End()
st, err := bs.StateFetcher.State(ctx, req.StateId)
st, err := bs.Stater.State(ctx, req.StateId)
if err != nil {
return nil, helpers.PrepareStateFetchGRPCError(err)
}
@@ -186,7 +186,7 @@ func (bs *Server) GetRandao(ctx context.Context, req *eth2.RandaoRequest) (*eth2
return nil, status.Errorf(codes.Internal, "Could not get randao mix at index %d", idx)
}
isOptimistic, err := helpers.IsOptimistic(ctx, st, bs.OptimisticModeFetcher)
isOptimistic, err := helpers.IsOptimistic(ctx, req.StateId, bs.OptimisticModeFetcher, bs.Stater, bs.ChainInfoFetcher, bs.BeaconDB)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not check if slot's block is optimistic: %v", err)
}
@@ -215,14 +215,14 @@ func (bs *Server) stateFromRequest(ctx context.Context, req *stateRequest) (stat
err,
)
}
st, err := bs.StateFetcher.State(ctx, []byte(strconv.FormatUint(uint64(slot), 10)))
st, err := bs.Stater.State(ctx, []byte(strconv.FormatUint(uint64(slot), 10)))
if err != nil {
return nil, helpers.PrepareStateFetchGRPCError(err)
}
return st, nil
}
var err error
st, err := bs.StateFetcher.State(ctx, req.stateId)
st, err := bs.Stater.State(ctx, req.stateId)
if err != nil {
return nil, helpers.PrepareStateFetchGRPCError(err)
}

View File

@@ -83,7 +83,7 @@ func TestGetStateRoot(t *testing.T) {
chainService := &chainMock.ChainService{}
server := &Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconStateRoot: stateRoot[:],
BeaconState: fakeState,
},
@@ -94,7 +94,7 @@ func TestGetStateRoot(t *testing.T) {
}
resp, err := server.GetStateRoot(context.Background(), &eth.StateRequest{
StateId: make([]byte, 0),
StateId: []byte("head"),
})
require.NoError(t, err)
assert.NotNil(t, resp)
@@ -111,7 +111,7 @@ func TestGetStateRoot(t *testing.T) {
chainService := &chainMock.ChainService{Optimistic: true}
server := &Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconStateRoot: stateRoot[:],
BeaconState: fakeState,
},
@@ -121,7 +121,7 @@ func TestGetStateRoot(t *testing.T) {
BeaconDB: db,
}
resp, err := server.GetStateRoot(context.Background(), &eth.StateRequest{
StateId: make([]byte, 0),
StateId: []byte("head"),
})
require.NoError(t, err)
assert.NotNil(t, resp)
@@ -145,7 +145,7 @@ func TestGetStateRoot(t *testing.T) {
},
}
server := &Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconStateRoot: stateRoot[:],
BeaconState: fakeState,
},
@@ -155,7 +155,7 @@ func TestGetStateRoot(t *testing.T) {
BeaconDB: db,
}
resp, err := server.GetStateRoot(context.Background(), &eth.StateRequest{
StateId: make([]byte, 0),
StateId: []byte("head"),
})
require.NoError(t, err)
assert.NotNil(t, resp)
@@ -179,7 +179,7 @@ func TestGetStateFork(t *testing.T) {
chainService := &chainMock.ChainService{}
server := &Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: fakeState,
},
HeadFetcher: chainService,
@@ -189,7 +189,7 @@ func TestGetStateFork(t *testing.T) {
}
resp, err := server.GetStateFork(ctx, &eth.StateRequest{
StateId: make([]byte, 0),
StateId: []byte("head"),
})
require.NoError(t, err)
assert.NotNil(t, resp)
@@ -209,7 +209,7 @@ func TestGetStateFork(t *testing.T) {
chainService := &chainMock.ChainService{Optimistic: true}
server := &Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: fakeState,
},
HeadFetcher: chainService,
@@ -218,7 +218,7 @@ func TestGetStateFork(t *testing.T) {
BeaconDB: db,
}
resp, err := server.GetStateFork(context.Background(), &eth.StateRequest{
StateId: make([]byte, 0),
StateId: []byte("head"),
})
require.NoError(t, err)
assert.NotNil(t, resp)
@@ -242,7 +242,7 @@ func TestGetStateFork(t *testing.T) {
},
}
server := &Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: fakeState,
},
HeadFetcher: chainService,
@@ -251,7 +251,7 @@ func TestGetStateFork(t *testing.T) {
BeaconDB: db,
}
resp, err := server.GetStateFork(context.Background(), &eth.StateRequest{
StateId: make([]byte, 0),
StateId: []byte("head"),
})
require.NoError(t, err)
assert.NotNil(t, resp)
@@ -282,7 +282,7 @@ func TestGetFinalityCheckpoints(t *testing.T) {
chainService := &chainMock.ChainService{}
server := &Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: fakeState,
},
HeadFetcher: chainService,
@@ -292,7 +292,7 @@ func TestGetFinalityCheckpoints(t *testing.T) {
}
resp, err := server.GetFinalityCheckpoints(ctx, &eth.StateRequest{
StateId: make([]byte, 0),
StateId: []byte("head"),
})
require.NoError(t, err)
assert.NotNil(t, resp)
@@ -314,7 +314,7 @@ func TestGetFinalityCheckpoints(t *testing.T) {
chainService := &chainMock.ChainService{Optimistic: true}
server := &Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: fakeState,
},
HeadFetcher: chainService,
@@ -323,7 +323,7 @@ func TestGetFinalityCheckpoints(t *testing.T) {
BeaconDB: db,
}
resp, err := server.GetFinalityCheckpoints(context.Background(), &eth.StateRequest{
StateId: make([]byte, 0),
StateId: []byte("head"),
})
require.NoError(t, err)
assert.NotNil(t, resp)
@@ -347,7 +347,7 @@ func TestGetFinalityCheckpoints(t *testing.T) {
},
}
server := &Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: fakeState,
},
HeadFetcher: chainService,
@@ -356,7 +356,7 @@ func TestGetFinalityCheckpoints(t *testing.T) {
BeaconDB: db,
}
resp, err := server.GetFinalityCheckpoints(context.Background(), &eth.StateRequest{
StateId: make([]byte, 0),
StateId: []byte("head"),
})
require.NoError(t, err)
assert.NotNil(t, resp)
@@ -388,7 +388,7 @@ func TestGetRandao(t *testing.T) {
db := dbTest.SetupDB(t)
chainService := &chainMock.ChainService{}
server := &Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
@@ -398,22 +398,22 @@ func TestGetRandao(t *testing.T) {
}
t.Run("no epoch requested", func(t *testing.T) {
resp, err := server.GetRandao(ctx, &eth2.RandaoRequest{StateId: make([]byte, 0)})
resp, err := server.GetRandao(ctx, &eth2.RandaoRequest{StateId: []byte("head")})
require.NoError(t, err)
assert.DeepEqual(t, mixCurrent, resp.Data.Randao)
})
t.Run("current epoch requested", func(t *testing.T) {
resp, err := server.GetRandao(ctx, &eth2.RandaoRequest{StateId: make([]byte, 0), Epoch: &epochCurrent})
resp, err := server.GetRandao(ctx, &eth2.RandaoRequest{StateId: []byte("head"), Epoch: &epochCurrent})
require.NoError(t, err)
assert.DeepEqual(t, mixCurrent, resp.Data.Randao)
})
t.Run("old epoch requested", func(t *testing.T) {
resp, err := server.GetRandao(ctx, &eth2.RandaoRequest{StateId: make([]byte, 0), Epoch: &epochOld})
resp, err := server.GetRandao(ctx, &eth2.RandaoRequest{StateId: []byte("head"), Epoch: &epochOld})
require.NoError(t, err)
assert.DeepEqual(t, mixOld, resp.Data.Randao)
})
t.Run("head state below `EpochsPerHistoricalVector`", func(t *testing.T) {
server.StateFetcher = &testutil.MockFetcher{
server.Stater = &testutil.MockStater{
BeaconState: headSt,
}
resp, err := server.GetRandao(ctx, &eth2.RandaoRequest{StateId: []byte("head")})
@@ -441,7 +441,7 @@ func TestGetRandao(t *testing.T) {
chainService := &chainMock.ChainService{Optimistic: true}
server := &Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
@@ -450,7 +450,7 @@ func TestGetRandao(t *testing.T) {
BeaconDB: db,
}
resp, err := server.GetRandao(context.Background(), &eth2.RandaoRequest{
StateId: make([]byte, 0),
StateId: []byte("head"),
})
require.NoError(t, err)
assert.NotNil(t, resp)
@@ -473,7 +473,7 @@ func TestGetRandao(t *testing.T) {
},
}
server := &Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
@@ -482,7 +482,7 @@ func TestGetRandao(t *testing.T) {
BeaconDB: db,
}
resp, err := server.GetRandao(context.Background(), &eth2.RandaoRequest{
StateId: make([]byte, 0),
StateId: []byte("head"),
})
require.NoError(t, err)
assert.NotNil(t, resp)

View File

@@ -91,7 +91,7 @@ func (bs *Server) ListSyncCommittees(ctx context.Context, req *ethpbv2.StateSync
return nil, status.Errorf(codes.Internal, "Could not extract sync subcommittees: %v", err)
}
isOptimistic, err := helpers.IsOptimistic(ctx, st, bs.OptimisticModeFetcher)
isOptimistic, err := helpers.IsOptimistic(ctx, req.StateId, bs.OptimisticModeFetcher, bs.Stater, bs.ChainInfoFetcher, bs.BeaconDB)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not check if slot's block is optimistic: %v", err)
}

View File

@@ -161,18 +161,20 @@ func TestListSyncCommittees(t *testing.T) {
require.NoError(t, err)
db := dbTest.SetupDB(t)
chainService := &mock.ChainService{}
stSlot := st.Slot()
chainService := &mock.ChainService{Slot: &stSlot}
s := &Server{
GenesisTimeFetcher: &testutil.MockGenesisTimeFetcher{
Genesis: time.Now(),
},
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
OptimisticModeFetcher: chainService,
FinalizationFetcher: chainService,
BeaconDB: db,
ChainInfoFetcher: chainService,
}
req := &ethpbv2.StateSyncCommitteesRequest{StateId: stRoot[:]}
resp, err := s.ListSyncCommittees(ctx, req)
@@ -205,18 +207,20 @@ func TestListSyncCommittees(t *testing.T) {
util.SaveBlock(t, ctx, db, blk)
require.NoError(t, db.SaveGenesisBlockRoot(ctx, root))
chainService := &mock.ChainService{Optimistic: true}
stSlot := st.Slot()
chainService := &mock.ChainService{Optimistic: true, Slot: &stSlot}
s := &Server{
GenesisTimeFetcher: &testutil.MockGenesisTimeFetcher{
Genesis: time.Now(),
},
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
OptimisticModeFetcher: chainService,
FinalizationFetcher: chainService,
BeaconDB: db,
ChainInfoFetcher: chainService,
}
resp, err := s.ListSyncCommittees(ctx, req)
require.NoError(t, err)
@@ -234,22 +238,25 @@ func TestListSyncCommittees(t *testing.T) {
headerRoot, err := st.LatestBlockHeader().HashTreeRoot()
require.NoError(t, err)
stSlot := st.Slot()
chainService := &mock.ChainService{
FinalizedRoots: map[[32]byte]bool{
headerRoot: true,
},
Slot: &stSlot,
}
s := &Server{
GenesisTimeFetcher: &testutil.MockGenesisTimeFetcher{
Genesis: time.Now(),
},
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
OptimisticModeFetcher: chainService,
FinalizationFetcher: chainService,
BeaconDB: db,
ChainInfoFetcher: chainService,
}
resp, err := s.ListSyncCommittees(ctx, req)
require.NoError(t, err)
@@ -302,7 +309,7 @@ func TestListSyncCommitteesFuture(t *testing.T) {
GenesisTimeFetcher: &testutil.MockGenesisTimeFetcher{
Genesis: time.Now(),
},
StateFetcher: &futureSyncMockFetcher{
Stater: &futureSyncMockFetcher{
BeaconState: st,
},
HeadFetcher: chainService,
@@ -310,7 +317,7 @@ func TestListSyncCommitteesFuture(t *testing.T) {
FinalizationFetcher: chainService,
BeaconDB: db,
}
req := &ethpbv2.StateSyncCommitteesRequest{}
req := &ethpbv2.StateSyncCommitteesRequest{StateId: []byte("head")}
epoch := 2 * params.BeaconConfig().EpochsPerSyncCommitteePeriod
req.Epoch = &epoch
_, err := s.ListSyncCommittees(ctx, req)

View File

@@ -42,7 +42,7 @@ func (bs *Server) GetValidator(ctx context.Context, req *ethpb.StateValidatorReq
ctx, span := trace.StartSpan(ctx, "beacon.GetValidator")
defer span.End()
st, err := bs.StateFetcher.State(ctx, req.StateId)
st, err := bs.Stater.State(ctx, req.StateId)
if err != nil {
return nil, helpers.PrepareStateFetchGRPCError(err)
}
@@ -57,7 +57,7 @@ func (bs *Server) GetValidator(ctx context.Context, req *ethpb.StateValidatorReq
return nil, status.Error(codes.NotFound, "Could not find validator")
}
isOptimistic, err := helpers.IsOptimistic(ctx, st, bs.OptimisticModeFetcher)
isOptimistic, err := helpers.IsOptimistic(ctx, req.StateId, bs.OptimisticModeFetcher, bs.Stater, bs.ChainInfoFetcher, bs.BeaconDB)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not check if slot's block is optimistic: %v", err)
}
@@ -76,7 +76,7 @@ func (bs *Server) ListValidators(ctx context.Context, req *ethpb.StateValidators
ctx, span := trace.StartSpan(ctx, "beacon.ListValidators")
defer span.End()
st, err := bs.StateFetcher.State(ctx, req.StateId)
st, err := bs.Stater.State(ctx, req.StateId)
if err != nil {
return nil, helpers.PrepareStateFetchGRPCError(err)
}
@@ -86,7 +86,7 @@ func (bs *Server) ListValidators(ctx context.Context, req *ethpb.StateValidators
return nil, handleValContainerErr(err)
}
isOptimistic, err := helpers.IsOptimistic(ctx, st, bs.OptimisticModeFetcher)
isOptimistic, err := helpers.IsOptimistic(ctx, req.StateId, bs.OptimisticModeFetcher, bs.Stater, bs.ChainInfoFetcher, bs.BeaconDB)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not check if slot's block is optimistic: %v", err)
}
@@ -138,7 +138,7 @@ func (bs *Server) ListValidatorBalances(ctx context.Context, req *ethpb.Validato
ctx, span := trace.StartSpan(ctx, "beacon.ListValidatorBalances")
defer span.End()
st, err := bs.StateFetcher.State(ctx, req.StateId)
st, err := bs.Stater.State(ctx, req.StateId)
if err != nil {
return nil, helpers.PrepareStateFetchGRPCError(err)
}
@@ -155,7 +155,7 @@ func (bs *Server) ListValidatorBalances(ctx context.Context, req *ethpb.Validato
}
}
isOptimistic, err := helpers.IsOptimistic(ctx, st, bs.OptimisticModeFetcher)
isOptimistic, err := helpers.IsOptimistic(ctx, req.StateId, bs.OptimisticModeFetcher, bs.Stater, bs.ChainInfoFetcher, bs.BeaconDB)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not check if slot's block is optimistic: %v", err)
}
@@ -175,7 +175,7 @@ func (bs *Server) ListCommittees(ctx context.Context, req *ethpb.StateCommittees
ctx, span := trace.StartSpan(ctx, "beacon.ListCommittees")
defer span.End()
st, err := bs.StateFetcher.State(ctx, req.StateId)
st, err := bs.Stater.State(ctx, req.StateId)
if err != nil {
return nil, helpers.PrepareStateFetchGRPCError(err)
}
@@ -220,7 +220,7 @@ func (bs *Server) ListCommittees(ctx context.Context, req *ethpb.StateCommittees
}
}
isOptimistic, err := helpers.IsOptimistic(ctx, st, bs.OptimisticModeFetcher)
isOptimistic, err := helpers.IsOptimistic(ctx, req.StateId, bs.OptimisticModeFetcher, bs.Stater, bs.ChainInfoFetcher, bs.BeaconDB)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not check if slot's block is optimistic: %v", err)
}

View File

@@ -9,7 +9,7 @@ import (
chainMock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing"
dbTest "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing"
rpchelpers "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/helpers"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/statefetcher"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/testutil"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
state_native "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native"
@@ -34,7 +34,7 @@ func TestGetValidator(t *testing.T) {
t.Run("Head Get Validator by index", func(t *testing.T) {
chainService := &chainMock.ChainService{}
s := Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
@@ -54,7 +54,7 @@ func TestGetValidator(t *testing.T) {
t.Run("Head Get Validator by pubkey", func(t *testing.T) {
chainService := &chainMock.ChainService{}
s := Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
@@ -75,7 +75,7 @@ func TestGetValidator(t *testing.T) {
t.Run("Validator ID required", func(t *testing.T) {
s := Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: &chainMock.ChainService{},
@@ -98,7 +98,7 @@ func TestGetValidator(t *testing.T) {
chainService := &chainMock.ChainService{Optimistic: true}
s := Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
@@ -131,7 +131,7 @@ func TestGetValidator(t *testing.T) {
},
}
s := Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
@@ -157,7 +157,7 @@ func TestListValidators(t *testing.T) {
t.Run("Head List All Validators", func(t *testing.T) {
chainService := &chainMock.ChainService{}
s := Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
@@ -179,7 +179,7 @@ func TestListValidators(t *testing.T) {
t.Run("Head List Validators by index", func(t *testing.T) {
chainService := &chainMock.ChainService{}
s := Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
@@ -204,7 +204,7 @@ func TestListValidators(t *testing.T) {
t.Run("Head List Validators by pubkey", func(t *testing.T) {
chainService := &chainMock.ChainService{}
s := Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
@@ -233,7 +233,7 @@ func TestListValidators(t *testing.T) {
t.Run("Head List Validators by both index and pubkey", func(t *testing.T) {
chainService := &chainMock.ChainService{}
s := Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
@@ -264,7 +264,7 @@ func TestListValidators(t *testing.T) {
t.Run("Unknown public key is ignored", func(t *testing.T) {
chainService := &chainMock.ChainService{}
s := Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
@@ -287,7 +287,7 @@ func TestListValidators(t *testing.T) {
t.Run("Unknown index is ignored", func(t *testing.T) {
chainService := &chainMock.ChainService{}
s := Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
@@ -317,7 +317,7 @@ func TestListValidators(t *testing.T) {
chainService := &chainMock.ChainService{Optimistic: true}
s := Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
@@ -349,7 +349,7 @@ func TestListValidators(t *testing.T) {
},
}
s := Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
@@ -440,7 +440,7 @@ func TestListValidators_Status(t *testing.T) {
t.Run("Head List All ACTIVE Validators", func(t *testing.T) {
chainService := &chainMock.ChainService{}
s := Server{
StateFetcher: &statefetcher.StateProvider{
Stater: &lookup.BeaconDbStater{
ChainInfoFetcher: &chainMock.ChainService{State: st},
},
HeadFetcher: chainService,
@@ -478,7 +478,7 @@ func TestListValidators_Status(t *testing.T) {
t.Run("Head List All ACTIVE_ONGOING Validators", func(t *testing.T) {
chainService := &chainMock.ChainService{}
s := Server{
StateFetcher: &statefetcher.StateProvider{
Stater: &lookup.BeaconDbStater{
ChainInfoFetcher: &chainMock.ChainService{State: st},
},
HeadFetcher: chainService,
@@ -515,7 +515,7 @@ func TestListValidators_Status(t *testing.T) {
t.Run("Head List All EXITED Validators", func(t *testing.T) {
chainService := &chainMock.ChainService{}
s := Server{
StateFetcher: &statefetcher.StateProvider{
Stater: &lookup.BeaconDbStater{
ChainInfoFetcher: &chainMock.ChainService{State: st},
},
HeadFetcher: chainService,
@@ -551,7 +551,7 @@ func TestListValidators_Status(t *testing.T) {
t.Run("Head List All PENDING_INITIALIZED and EXITED_UNSLASHED Validators", func(t *testing.T) {
chainService := &chainMock.ChainService{}
s := Server{
StateFetcher: &statefetcher.StateProvider{
Stater: &lookup.BeaconDbStater{
ChainInfoFetcher: &chainMock.ChainService{State: st},
},
HeadFetcher: chainService,
@@ -587,7 +587,7 @@ func TestListValidators_Status(t *testing.T) {
t.Run("Head List All PENDING and EXITED Validators", func(t *testing.T) {
chainService := &chainMock.ChainService{}
s := Server{
StateFetcher: &statefetcher.StateProvider{
Stater: &lookup.BeaconDbStater{
ChainInfoFetcher: &chainMock.ChainService{State: st},
},
HeadFetcher: chainService,
@@ -638,7 +638,7 @@ func TestListValidatorBalances(t *testing.T) {
t.Run("Head List Validators Balance by index", func(t *testing.T) {
chainService := &chainMock.ChainService{}
s := Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
@@ -663,7 +663,7 @@ func TestListValidatorBalances(t *testing.T) {
t.Run("Head List Validators Balance by pubkey", func(t *testing.T) {
chainService := &chainMock.ChainService{}
s := Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
@@ -691,7 +691,7 @@ func TestListValidatorBalances(t *testing.T) {
t.Run("Head List Validators Balance by both index and pubkey", func(t *testing.T) {
chainService := &chainMock.ChainService{}
s := Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
@@ -726,7 +726,7 @@ func TestListValidatorBalances(t *testing.T) {
chainService := &chainMock.ChainService{Optimistic: true}
s := Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
@@ -761,7 +761,7 @@ func TestListValidatorBalances(t *testing.T) {
},
}
s := Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
@@ -791,7 +791,7 @@ func TestListCommittees(t *testing.T) {
t.Run("Head All Committees", func(t *testing.T) {
chainService := &chainMock.ChainService{}
s := Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
@@ -814,7 +814,7 @@ func TestListCommittees(t *testing.T) {
t.Run("Head All Committees of Epoch 10", func(t *testing.T) {
chainService := &chainMock.ChainService{}
s := Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
@@ -836,7 +836,7 @@ func TestListCommittees(t *testing.T) {
t.Run("Head All Committees of Slot 4", func(t *testing.T) {
chainService := &chainMock.ChainService{}
s := Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
@@ -864,7 +864,7 @@ func TestListCommittees(t *testing.T) {
t.Run("Head All Committees of Index 1", func(t *testing.T) {
chainService := &chainMock.ChainService{}
s := Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
@@ -892,7 +892,7 @@ func TestListCommittees(t *testing.T) {
t.Run("Head All Committees of Slot 2, Index 1", func(t *testing.T) {
chainService := &chainMock.ChainService{}
s := Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
@@ -928,7 +928,7 @@ func TestListCommittees(t *testing.T) {
chainService := &chainMock.ChainService{Optimistic: true}
s := Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
@@ -961,7 +961,7 @@ func TestListCommittees(t *testing.T) {
},
}
s := Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,

View File

@@ -12,7 +12,7 @@ go_library(
"//beacon-chain/blockchain:go_default_library",
"//beacon-chain/db:go_default_library",
"//beacon-chain/rpc/eth/helpers:go_default_library",
"//beacon-chain/rpc/statefetcher:go_default_library",
"//beacon-chain/rpc/lookup:go_default_library",
"//proto/eth/v1:go_default_library",
"//proto/eth/v2:go_default_library",
"//proto/migration:go_default_library",

View File

@@ -19,7 +19,7 @@ func (ds *Server) GetBeaconStateSSZ(ctx context.Context, req *ethpbv1.StateReque
ctx, span := trace.StartSpan(ctx, "debug.GetBeaconStateSSZ")
defer span.End()
state, err := ds.StateFetcher.State(ctx, req.StateId)
state, err := ds.Stater.State(ctx, req.StateId)
if err != nil {
return nil, helpers.PrepareStateFetchGRPCError(err)
}
@@ -37,11 +37,11 @@ func (ds *Server) GetBeaconStateV2(ctx context.Context, req *ethpbv2.BeaconState
ctx, span := trace.StartSpan(ctx, "debug.GetBeaconStateV2")
defer span.End()
beaconSt, err := ds.StateFetcher.State(ctx, req.StateId)
beaconSt, err := ds.Stater.State(ctx, req.StateId)
if err != nil {
return nil, helpers.PrepareStateFetchGRPCError(err)
}
isOptimistic, err := helpers.IsOptimistic(ctx, beaconSt, ds.OptimisticModeFetcher)
isOptimistic, err := helpers.IsOptimistic(ctx, req.StateId, ds.OptimisticModeFetcher, ds.Stater, ds.ChainInfoFetcher, ds.BeaconDB)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not check if slot's block is optimistic: %v", err)
}
@@ -114,7 +114,7 @@ func (ds *Server) GetBeaconStateSSZV2(ctx context.Context, req *ethpbv2.BeaconSt
ctx, span := trace.StartSpan(ctx, "debug.GetBeaconStateSSZV2")
defer span.End()
st, err := ds.StateFetcher.State(ctx, req.StateId)
st, err := ds.Stater.State(ctx, req.StateId)
if err != nil {
return nil, helpers.PrepareStateFetchGRPCError(err)
}
@@ -166,7 +166,5 @@ func (ds *Server) ListForkChoiceHeadsV2(ctx context.Context, _ *emptypb.Empty) (
// GetForkChoice returns a dump fork choice store.
func (ds *Server) GetForkChoice(ctx context.Context, _ *emptypb.Empty) (*ethpbv1.ForkChoiceDump, error) {
ds.ForkFetcher.ForkChoicer().RLock()
defer ds.ForkFetcher.ForkChoicer().RUnlock()
return ds.ForkFetcher.ForkChoicer().ForkChoiceDump(ctx)
return ds.ForkchoiceFetcher.ForkChoiceDump(ctx)
}

View File

@@ -28,7 +28,7 @@ func TestGetBeaconStateV2(t *testing.T) {
fakeState, err := util.NewBeaconState()
require.NoError(t, err)
server := &Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: fakeState,
},
HeadFetcher: &blockchainmock.ChainService{},
@@ -37,7 +37,7 @@ func TestGetBeaconStateV2(t *testing.T) {
BeaconDB: db,
}
resp, err := server.GetBeaconStateV2(context.Background(), &ethpbv2.BeaconStateRequestV2{
StateId: make([]byte, 0),
StateId: []byte("head"),
})
require.NoError(t, err)
assert.NotNil(t, resp)
@@ -46,7 +46,7 @@ func TestGetBeaconStateV2(t *testing.T) {
t.Run("Altair", func(t *testing.T) {
fakeState, _ := util.DeterministicGenesisStateAltair(t, 1)
server := &Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: fakeState,
},
HeadFetcher: &blockchainmock.ChainService{},
@@ -55,7 +55,7 @@ func TestGetBeaconStateV2(t *testing.T) {
BeaconDB: db,
}
resp, err := server.GetBeaconStateV2(context.Background(), &ethpbv2.BeaconStateRequestV2{
StateId: make([]byte, 0),
StateId: []byte("head"),
})
require.NoError(t, err)
assert.NotNil(t, resp)
@@ -64,7 +64,7 @@ func TestGetBeaconStateV2(t *testing.T) {
t.Run("Bellatrix", func(t *testing.T) {
fakeState, _ := util.DeterministicGenesisStateBellatrix(t, 1)
server := &Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: fakeState,
},
HeadFetcher: &blockchainmock.ChainService{},
@@ -73,7 +73,7 @@ func TestGetBeaconStateV2(t *testing.T) {
BeaconDB: db,
}
resp, err := server.GetBeaconStateV2(context.Background(), &ethpbv2.BeaconStateRequestV2{
StateId: make([]byte, 0),
StateId: []byte("head"),
})
require.NoError(t, err)
assert.NotNil(t, resp)
@@ -82,7 +82,7 @@ func TestGetBeaconStateV2(t *testing.T) {
t.Run("Capella", func(t *testing.T) {
fakeState, _ := util.DeterministicGenesisStateCapella(t, 1)
server := &Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: fakeState,
},
HeadFetcher: &blockchainmock.ChainService{},
@@ -91,7 +91,7 @@ func TestGetBeaconStateV2(t *testing.T) {
BeaconDB: db,
}
resp, err := server.GetBeaconStateV2(context.Background(), &ethpbv2.BeaconStateRequestV2{
StateId: make([]byte, 0),
StateId: []byte("head"),
})
require.NoError(t, err)
assert.NotNil(t, resp)
@@ -108,7 +108,7 @@ func TestGetBeaconStateV2(t *testing.T) {
fakeState, _ := util.DeterministicGenesisStateBellatrix(t, 1)
server := &Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: fakeState,
},
HeadFetcher: &blockchainmock.ChainService{},
@@ -117,7 +117,7 @@ func TestGetBeaconStateV2(t *testing.T) {
BeaconDB: db,
}
resp, err := server.GetBeaconStateV2(context.Background(), &ethpbv2.BeaconStateRequestV2{
StateId: make([]byte, 0),
StateId: []byte("head"),
})
require.NoError(t, err)
assert.NotNil(t, resp)
@@ -141,7 +141,7 @@ func TestGetBeaconStateV2(t *testing.T) {
},
}
server := &Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: fakeState,
},
HeadFetcher: chainService,
@@ -150,7 +150,7 @@ func TestGetBeaconStateV2(t *testing.T) {
BeaconDB: db,
}
resp, err := server.GetBeaconStateV2(context.Background(), &ethpbv2.BeaconStateRequestV2{
StateId: make([]byte, 0),
StateId: []byte("head"),
})
require.NoError(t, err)
assert.NotNil(t, resp)
@@ -165,7 +165,7 @@ func TestGetBeaconStateSSZ(t *testing.T) {
require.NoError(t, err)
server := &Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: fakeState,
},
}
@@ -186,7 +186,7 @@ func TestGetBeaconStateSSZV2(t *testing.T) {
require.NoError(t, err)
server := &Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: fakeState,
},
}
@@ -205,7 +205,7 @@ func TestGetBeaconStateSSZV2(t *testing.T) {
require.NoError(t, err)
server := &Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: fakeState,
},
}
@@ -224,7 +224,7 @@ func TestGetBeaconStateSSZV2(t *testing.T) {
require.NoError(t, err)
server := &Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: fakeState,
},
}
@@ -243,7 +243,7 @@ func TestGetBeaconStateSSZV2(t *testing.T) {
require.NoError(t, err)
server := &Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
BeaconState: fakeState,
},
}
@@ -293,7 +293,13 @@ func TestListForkChoiceHeadsV2(t *testing.T) {
}
t.Run("optimistic head", func(t *testing.T) {
chainService := &blockchainmock.ChainService{Optimistic: true}
chainService := &blockchainmock.ChainService{
Optimistic: true,
OptimisticRoots: make(map[[32]byte]bool),
}
for _, sr := range expectedSlotsAndRoots {
chainService.OptimisticRoots[sr.Root] = true
}
server := &Server{
HeadFetcher: chainService,
OptimisticModeFetcher: chainService,
@@ -320,7 +326,7 @@ func TestServer_GetForkChoice(t *testing.T) {
fRoot := [32]byte{'a'}
fc := &forkchoicetypes.Checkpoint{Epoch: 2, Root: fRoot}
require.NoError(t, store.UpdateFinalizedCheckpoint(fc))
bs := &Server{ForkFetcher: &blockchainmock.ChainService{ForkChoiceStore: store}}
bs := &Server{ForkchoiceFetcher: &blockchainmock.ChainService{ForkChoiceStore: store}}
res, err := bs.GetForkChoice(context.Background(), &empty.Empty{})
require.NoError(t, err)
require.Equal(t, primitives.Epoch(2), res.FinalizedCheckpoint.Epoch, "Did not get wanted finalized epoch")

View File

@@ -6,7 +6,7 @@ package debug
import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/db"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/statefetcher"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup"
)
// Server defines a server implementation of the gRPC Beacon Chain service,
@@ -14,8 +14,10 @@ import (
type Server struct {
BeaconDB db.ReadOnlyDatabase
HeadFetcher blockchain.HeadFetcher
StateFetcher statefetcher.Fetcher
Stater lookup.Stater
OptimisticModeFetcher blockchain.OptimisticModeFetcher
ForkFetcher blockchain.ForkFetcher
ForkchoiceFetcher blockchain.ForkchoiceFetcher
FinalizationFetcher blockchain.FinalizationFetcher
ChainInfoFetcher blockchain.ChainInfoFetcher
}

View File

@@ -261,9 +261,13 @@ func (s *Server) handleStateEvents(
// This event stream is intended to be used by builders and relays.
// parent_ fields are based on state at N_{current_slot}, while the rest of fields are based on state of N_{current_slot + 1}
func (s *Server) streamPayloadAttributes(stream ethpbservice.Events_StreamEventsServer) error {
headRoot, err := s.HeadFetcher.HeadRoot(s.Ctx)
if err != nil {
return errors.Wrap(err, "could not get head root")
}
st, err := s.HeadFetcher.HeadState(s.Ctx)
if err != nil {
return err
return errors.Wrap(err, "could not get head state")
}
// advance the headstate
headState, err := transition.ProcessSlotsIfPossible(s.Ctx, st, s.ChainInfoFetcher.CurrentSlot()+1)
@@ -276,11 +280,6 @@ func (s *Server) streamPayloadAttributes(stream ethpbservice.Events_StreamEvents
return err
}
headRoot, err := s.HeadFetcher.HeadRoot(s.Ctx)
if err != nil {
return err
}
headPayload, err := headBlock.Block().Body().Execution()
if err != nil {
return err
@@ -331,7 +330,7 @@ func (s *Server) streamPayloadAttributes(stream ethpbservice.Events_StreamEvents
ParentBlockNumber: headPayload.BlockNumber(),
ParentBlockRoot: headRoot,
ParentBlockHash: headPayload.BlockHash(),
PayloadAttributesV2: &enginev1.PayloadAttributesV2{
PayloadAttributes: &enginev1.PayloadAttributesV2{
Timestamp: uint64(t.Unix()),
PrevRandao: prevRando,
SuggestedFeeRecipient: headPayload.FeeRecipient(),

View File

@@ -494,7 +494,7 @@ func TestStreamEvents_StateEvents(t *testing.T) {
ParentBlockNumber: 1,
ParentBlockRoot: make([]byte, 32),
ParentBlockHash: make([]byte, 32),
PayloadAttributesV2: &enginev1.PayloadAttributesV2{
PayloadAttributes: &enginev1.PayloadAttributesV2{
Timestamp: 24,
PrevRandao: prevRando,
SuggestedFeeRecipient: make([]byte, 20),

View File

@@ -12,13 +12,16 @@ go_library(
deps = [
"//api/grpc:go_default_library",
"//beacon-chain/blockchain:go_default_library",
"//beacon-chain/rpc/statefetcher:go_default_library",
"//beacon-chain/db:go_default_library",
"//beacon-chain/rpc/lookup:go_default_library",
"//beacon-chain/state:go_default_library",
"//beacon-chain/state/stategen:go_default_library",
"//beacon-chain/sync:go_default_library",
"//config/params:go_default_library",
"//consensus-types/primitives:go_default_library",
"//encoding/bytesutil:go_default_library",
"//proto/eth/v1:go_default_library",
"//time/slots: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",
@@ -35,12 +38,21 @@ go_test(
deps = [
"//api/grpc:go_default_library",
"//beacon-chain/blockchain/testing:go_default_library",
"//beacon-chain/db/testing:go_default_library",
"//beacon-chain/forkchoice/doubly-linked-tree:go_default_library",
"//beacon-chain/rpc/testutil:go_default_library",
"//beacon-chain/state:go_default_library",
"//beacon-chain/state/state-native:go_default_library",
"//beacon-chain/sync/initial-sync/testing:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//consensus-types/blocks:go_default_library",
"//consensus-types/primitives:go_default_library",
"//encoding/bytesutil:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/eth/v1:go_default_library",
"//proto/migration:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//testing/assert:go_default_library",
"//testing/require:go_default_library",
"//testing/util:go_default_library",

View File

@@ -3,7 +3,7 @@ package helpers
import (
"errors"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/statefetcher"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
@@ -15,10 +15,10 @@ func PrepareStateFetchGRPCError(err error) error {
if errors.Is(err, stategen.ErrNoDataForSlot) {
return status.Errorf(codes.NotFound, "lacking historical data needed to fulfill request")
}
if stateNotFoundErr, ok := err.(*statefetcher.StateNotFoundError); ok {
if stateNotFoundErr, ok := err.(*lookup.StateNotFoundError); ok {
return status.Errorf(codes.NotFound, "State not found: %v", stateNotFoundErr)
}
if parseErr, ok := err.(*statefetcher.StateIdParseError); ok {
if parseErr, ok := err.(*lookup.StateIdParseError); ok {
return status.Errorf(codes.InvalidArgument, "Invalid state ID: %v", parseErr)
}
return status.Errorf(codes.Internal, "Invalid state ID: %v", err)

View File

@@ -4,13 +4,18 @@ import (
"bytes"
"context"
"strconv"
"strings"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v4/api/grpc"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/db"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/sync"
"github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v4/time/slots"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
@@ -53,26 +58,134 @@ func ValidateSync(
return status.Error(codes.Unavailable, "Syncing to latest head, not ready to respond")
}
// IsOptimistic checks whether the latest block header of the passed in beacon state is the header of an optimistic block.
func IsOptimistic(ctx context.Context, st state.BeaconState, optimisticModeFetcher blockchain.OptimisticModeFetcher) (bool, error) {
header := st.LatestBlockHeader()
// This happens when the block at the state's slot is not missing.
if bytes.Equal(header.StateRoot, params.BeaconConfig().ZeroHash[:]) {
root, err := st.HashTreeRoot(ctx)
if err != nil {
return false, errors.Wrap(err, "could not get state root")
// IsOptimistic checks whether the beacon state's block is optimistic.
func IsOptimistic(
ctx context.Context,
stateId []byte,
optimisticModeFetcher blockchain.OptimisticModeFetcher,
stateFetcher lookup.Stater,
chainInfo blockchain.ChainInfoFetcher,
database db.ReadOnlyDatabase,
) (bool, error) {
stateIdString := strings.ToLower(string(stateId))
switch stateIdString {
case "head":
return optimisticModeFetcher.IsOptimistic(ctx)
case "genesis":
return false, nil
case "finalized":
fcp := chainInfo.FinalizedCheckpt()
if fcp == nil {
return true, errors.New("received nil finalized checkpoint")
}
// Special genesis case in the event our checkpoint root is a zerohash.
if bytes.Equal(fcp.Root, params.BeaconConfig().ZeroHash[:]) {
return false, nil
}
return optimisticModeFetcher.IsOptimisticForRoot(ctx, bytesutil.ToBytes32(fcp.Root))
case "justified":
jcp := chainInfo.CurrentJustifiedCheckpt()
if jcp == nil {
return true, errors.New("received nil justified checkpoint")
}
// Special genesis case in the event our checkpoint root is a zerohash.
if bytes.Equal(jcp.Root, params.BeaconConfig().ZeroHash[:]) {
return false, nil
}
return optimisticModeFetcher.IsOptimisticForRoot(ctx, bytesutil.ToBytes32(jcp.Root))
default:
if len(stateId) == 32 {
return isStateRootOptimistic(ctx, stateId, optimisticModeFetcher, stateFetcher, chainInfo, database)
} else {
optimistic, err := optimisticModeFetcher.IsOptimistic(ctx)
if err != nil {
return true, errors.Wrap(err, "could not check optimistic status")
}
if !optimistic {
return false, nil
}
slotNumber, parseErr := strconv.ParseUint(stateIdString, 10, 64)
if parseErr != nil {
// ID format does not match any valid options.
e := lookup.NewStateIdParseError(parseErr)
return true, &e
}
fcp := chainInfo.FinalizedCheckpt()
if fcp == nil {
return true, errors.New("received nil finalized checkpoint")
}
finalizedSlot, err := slots.EpochStart(fcp.Epoch)
if err != nil {
return true, errors.Wrap(err, "could not get head state's finalized slot")
}
lastValidatedCheckpoint, err := database.LastValidatedCheckpoint(ctx)
if err != nil {
return true, errors.Wrap(err, "could not get last validated checkpoint")
}
validatedSlot, err := slots.EpochStart(lastValidatedCheckpoint.Epoch)
if err != nil {
return true, errors.Wrap(err, "could not get last validated slot")
}
if primitives.Slot(slotNumber) <= validatedSlot {
return false, nil
}
// if the finalized checkpoint is higher than the last
// validated checkpoint, we are syncing and have synced
// a finalization being optimistic
if validatedSlot < finalizedSlot {
return true, nil
}
if primitives.Slot(slotNumber) == chainInfo.HeadSlot() {
// We know the head is optimistic because we checked it above.
return true, nil
}
headRoot, err := chainInfo.HeadRoot(ctx)
if err != nil {
return true, errors.Wrap(err, "could not get head root")
}
r, err := chainInfo.Ancestor(ctx, headRoot, primitives.Slot(slotNumber))
if err != nil {
return true, errors.Wrap(err, "could not get ancestor root")
}
return optimisticModeFetcher.IsOptimisticForRoot(ctx, bytesutil.ToBytes32(r))
}
header.StateRoot = root[:]
}
headRoot, err := header.HashTreeRoot()
}
func isStateRootOptimistic(
ctx context.Context,
stateId []byte,
optimisticModeFetcher blockchain.OptimisticModeFetcher,
stateFetcher lookup.Stater,
chainInfo blockchain.ChainInfoFetcher,
database db.ReadOnlyDatabase,
) (bool, error) {
st, err := stateFetcher.State(ctx, stateId)
if err != nil {
return false, errors.Wrap(err, "could not get header root")
return true, errors.Wrap(err, "could not fetch state")
}
isOptimistic, err := optimisticModeFetcher.IsOptimisticForRoot(ctx, headRoot)
if st.Slot() == chainInfo.HeadSlot() {
return optimisticModeFetcher.IsOptimistic(ctx)
}
has, roots, err := database.BlockRootsBySlot(ctx, st.Slot())
if err != nil {
return false, errors.Wrap(err, "could not check if block is optimistic")
return true, errors.Wrapf(err, "could not get block roots for slot %d", st.Slot())
}
return isOptimistic, nil
if !has {
return true, errors.New("no block roots returned from the database")
}
for _, r := range roots {
b, err := database.Block(ctx, r)
if err != nil {
return true, errors.Wrapf(err, "could not obtain block")
}
if bytesutil.ToBytes32(stateId) != b.Block().StateRoot() {
continue
}
return optimisticModeFetcher.IsOptimisticForRoot(ctx, r)
}
// No block matching requested state root, return true.
return true, nil
}
// SyncDetailsJson contains information about node sync status.

View File

@@ -2,14 +2,26 @@ package helpers
import (
"context"
"strconv"
"strings"
"testing"
"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"
dbtest "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing"
doublylinkedtree "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/doubly-linked-tree"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/testutil"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
state_native "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native"
syncmock "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync/initial-sync/testing"
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/primitives"
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
enginev1 "github.com/prysmaticlabs/prysm/v4/proto/engine/v1"
eth "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v4/testing/assert"
"github.com/prysmaticlabs/prysm/v4/testing/require"
"github.com/prysmaticlabs/prysm/v4/testing/util"
@@ -62,44 +74,257 @@ func TestValidateSync(t *testing.T) {
func TestIsOptimistic(t *testing.T) {
ctx := context.Background()
st, err := util.NewBeaconState()
require.NoError(t, err)
t.Run("optimistic", func(t *testing.T) {
mockOptSyncFetcher := &chainmock.ChainService{Optimistic: true}
o, err := IsOptimistic(ctx, st, mockOptSyncFetcher)
t.Run("head optimistic", func(t *testing.T) {
cs := &chainmock.ChainService{Optimistic: true}
o, err := IsOptimistic(ctx, []byte("head"), cs, nil, nil, nil)
require.NoError(t, err)
assert.Equal(t, true, o)
})
t.Run("not optimistic", func(t *testing.T) {
mockOptSyncFetcher := &chainmock.ChainService{Optimistic: false}
o, err := IsOptimistic(ctx, st, mockOptSyncFetcher)
t.Run("head not optimistic", func(t *testing.T) {
cs := &chainmock.ChainService{Optimistic: false}
o, err := IsOptimistic(ctx, []byte("head"), cs, nil, nil, nil)
require.NoError(t, err)
assert.Equal(t, false, o)
})
t.Run("zero state root", func(t *testing.T) {
zeroRootSt, err := util.NewBeaconState()
t.Run("genesis", func(t *testing.T) {
o, err := IsOptimistic(ctx, []byte("genesis"), nil, nil, nil, nil)
require.NoError(t, err)
h := zeroRootSt.LatestBlockHeader()
h.StateRoot = make([]byte, 32)
require.NoError(t, zeroRootSt.SetLatestBlockHeader(h))
mockOptSyncFetcher := &chainmock.ChainService{}
_, err = IsOptimistic(ctx, st, mockOptSyncFetcher)
require.NoError(t, err)
assert.DeepEqual(
t,
[32]byte{0xfc, 0x0, 0xe9, 0x6d, 0xb, 0x8b, 0x2, 0x2f, 0x61, 0xeb, 0x92, 0x10, 0xfd, 0x80, 0x84, 0x2b, 0x26, 0x61, 0xdc, 0x94, 0x5f, 0x7a, 0xf0, 0x0, 0xbc, 0x38, 0x6, 0x38, 0x71, 0x95, 0x43, 0x1},
mockOptSyncFetcher.OptimisticCheckRootReceived,
)
assert.Equal(t, false, o)
})
t.Run("non-zero state root", func(t *testing.T) {
mockOptSyncFetcher := &chainmock.ChainService{}
_, err = IsOptimistic(ctx, st, mockOptSyncFetcher)
require.NoError(t, err)
assert.DeepEqual(
t,
[32]byte{0xfc, 0x0, 0xe9, 0x6d, 0xb, 0x8b, 0x2, 0x2f, 0x61, 0xeb, 0x92, 0x10, 0xfd, 0x80, 0x84, 0x2b, 0x26, 0x61, 0xdc, 0x94, 0x5f, 0x7a, 0xf0, 0x0, 0xbc, 0x38, 0x6, 0x38, 0x71, 0x95, 0x43, 0x1},
mockOptSyncFetcher.OptimisticCheckRootReceived,
)
t.Run("finalized", func(t *testing.T) {
t.Run("finalized checkpoint is optimistic", func(t *testing.T) {
st, err := util.NewBeaconState()
require.NoError(t, err)
cs := &chainmock.ChainService{Optimistic: true, FinalizedCheckPoint: &eth.Checkpoint{}, OptimisticRoots: map[[32]byte]bool{[32]byte{}: true}}
mf := &testutil.MockStater{BeaconState: st}
o, err := IsOptimistic(ctx, []byte("finalized"), cs, mf, cs, nil)
require.NoError(t, err)
assert.Equal(t, true, o)
})
t.Run("finalized checkpoint is not optimistic", func(t *testing.T) {
st, err := util.NewBeaconState()
require.NoError(t, err)
cs := &chainmock.ChainService{Optimistic: true, FinalizedCheckPoint: &eth.Checkpoint{}}
mf := &testutil.MockStater{BeaconState: st}
o, err := IsOptimistic(ctx, []byte("finalized"), cs, mf, cs, nil)
require.NoError(t, err)
assert.Equal(t, false, o)
})
})
t.Run("justified", func(t *testing.T) {
t.Run("justified checkpoint is optimistic", func(t *testing.T) {
st, err := util.NewBeaconState()
require.NoError(t, err)
cs := &chainmock.ChainService{Optimistic: true, CurrentJustifiedCheckPoint: &eth.Checkpoint{}, OptimisticRoots: map[[32]byte]bool{[32]byte{}: true}}
mf := &testutil.MockStater{BeaconState: st}
o, err := IsOptimistic(ctx, []byte("justified"), cs, mf, cs, nil)
require.NoError(t, err)
assert.Equal(t, true, o)
})
t.Run("justified checkpoint is not optimistic", func(t *testing.T) {
st, err := util.NewBeaconState()
require.NoError(t, err)
cs := &chainmock.ChainService{Optimistic: true, CurrentJustifiedCheckPoint: &eth.Checkpoint{}}
mf := &testutil.MockStater{BeaconState: st}
o, err := IsOptimistic(ctx, []byte("justified"), cs, mf, cs, nil)
require.NoError(t, err)
assert.Equal(t, false, o)
})
})
t.Run("root", 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, 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, 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, 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, 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, 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}
o, err := IsOptimistic(ctx, []byte("0"), cs, nil, nil, nil)
require.NoError(t, err)
assert.Equal(t, false, o)
})
t.Run("is before validated slot when head is optimistic", func(t *testing.T) {
db := dbtest.SetupDB(t)
require.NoError(t, db.SaveStateSummary(ctx, &eth.StateSummary{Slot: fieldparams.SlotsPerEpoch, Root: []byte("root")}))
require.NoError(t, db.SaveLastValidatedCheckpoint(ctx, &eth.Checkpoint{Epoch: 1, Root: []byte("root")}))
cs := &chainmock.ChainService{Optimistic: true, FinalizedCheckPoint: &eth.Checkpoint{Epoch: 1}}
o, err := IsOptimistic(ctx, []byte("0"), cs, nil, cs, db)
require.NoError(t, err)
assert.Equal(t, false, o)
})
t.Run("is equal to validated slot when head is optimistic", func(t *testing.T) {
db := dbtest.SetupDB(t)
require.NoError(t, db.SaveStateSummary(ctx, &eth.StateSummary{Slot: fieldparams.SlotsPerEpoch, Root: []byte("root")}))
require.NoError(t, db.SaveLastValidatedCheckpoint(ctx, &eth.Checkpoint{Epoch: 1, Root: []byte("root")}))
cs := &chainmock.ChainService{Optimistic: true, FinalizedCheckPoint: &eth.Checkpoint{Epoch: 1}}
o, err := IsOptimistic(ctx, []byte("32"), cs, nil, cs, db)
require.NoError(t, err)
assert.Equal(t, false, o)
})
t.Run("is after validated slot and validated slot is before finalized slot", func(t *testing.T) {
db := dbtest.SetupDB(t)
require.NoError(t, db.SaveStateSummary(ctx, &eth.StateSummary{Slot: fieldparams.SlotsPerEpoch, Root: []byte("root")}))
require.NoError(t, db.SaveLastValidatedCheckpoint(ctx, &eth.Checkpoint{Epoch: 1, Root: []byte("root")}))
cs := &chainmock.ChainService{Optimistic: true, FinalizedCheckPoint: &eth.Checkpoint{Epoch: 2}}
o, err := IsOptimistic(ctx, []byte("33"), cs, nil, cs, db)
require.NoError(t, err)
assert.Equal(t, true, o)
})
t.Run("is head", func(t *testing.T) {
db := dbtest.SetupDB(t)
require.NoError(t, db.SaveStateSummary(ctx, &eth.StateSummary{Slot: fieldparams.SlotsPerEpoch, Root: []byte("root")}))
require.NoError(t, db.SaveLastValidatedCheckpoint(ctx, &eth.Checkpoint{Epoch: 1, Root: []byte("root")}))
fetcherSt, err := util.NewBeaconState()
require.NoError(t, err)
chainSt, err := util.NewBeaconState()
require.NoError(t, err)
require.NoError(t, chainSt.SetSlot(fieldparams.SlotsPerEpoch*2))
cs := &chainmock.ChainService{Optimistic: true, State: chainSt, FinalizedCheckPoint: &eth.Checkpoint{Epoch: 0}}
mf := &testutil.MockStater{BeaconState: fetcherSt}
o, err := IsOptimistic(ctx, []byte(strconv.Itoa(fieldparams.SlotsPerEpoch*2)), cs, mf, cs, db)
require.NoError(t, err)
assert.Equal(t, true, o)
})
t.Run("ancestor is optimistic", func(t *testing.T) {
db := dbtest.SetupDB(t)
require.NoError(t, db.SaveStateSummary(ctx, &eth.StateSummary{Slot: fieldparams.SlotsPerEpoch, Root: []byte("root")}))
require.NoError(t, db.SaveLastValidatedCheckpoint(ctx, &eth.Checkpoint{Epoch: 1, Root: []byte("root")}))
r := bytesutil.ToBytes32([]byte("root"))
fcs := doublylinkedtree.New()
finalizedCheckpt := &eth.Checkpoint{Epoch: 0}
st, root, err := prepareForkchoiceState(fieldparams.SlotsPerEpoch*2, r, [32]byte{}, [32]byte{}, finalizedCheckpt, finalizedCheckpt)
require.NoError(t, err)
require.NoError(t, fcs.InsertNode(ctx, st, root))
headRoot := [32]byte{'r'}
st, root, err = prepareForkchoiceState(fieldparams.SlotsPerEpoch*2+1, headRoot, r, [32]byte{}, finalizedCheckpt, finalizedCheckpt)
require.NoError(t, err)
require.NoError(t, fcs.InsertNode(ctx, st, root))
cs := &chainmock.ChainService{Root: headRoot[:], Optimistic: true, ForkChoiceStore: fcs, OptimisticRoots: map[[32]byte]bool{r: true}, FinalizedCheckPoint: finalizedCheckpt}
mf := &testutil.MockStater{BeaconState: st}
o, err := IsOptimistic(ctx, []byte(strconv.Itoa(fieldparams.SlotsPerEpoch*2)), cs, mf, cs, db)
require.NoError(t, err)
assert.Equal(t, true, o)
})
t.Run("ancestor is not optimistic", func(t *testing.T) {
db := dbtest.SetupDB(t)
require.NoError(t, db.SaveStateSummary(ctx, &eth.StateSummary{Slot: fieldparams.SlotsPerEpoch, Root: []byte("root")}))
require.NoError(t, db.SaveLastValidatedCheckpoint(ctx, &eth.Checkpoint{Epoch: 1, Root: []byte("root")}))
r := bytesutil.ToBytes32([]byte("root"))
fcs := doublylinkedtree.New()
finalizedCheckpt := &eth.Checkpoint{Epoch: 0}
st, root, err := prepareForkchoiceState(fieldparams.SlotsPerEpoch*2, r, [32]byte{}, [32]byte{}, finalizedCheckpt, finalizedCheckpt)
require.NoError(t, err)
require.NoError(t, fcs.InsertNode(ctx, st, root))
headRoot := [32]byte{'r'}
st, root, err = prepareForkchoiceState(fieldparams.SlotsPerEpoch*2+1, headRoot, r, [32]byte{}, finalizedCheckpt, finalizedCheckpt)
require.NoError(t, err)
require.NoError(t, fcs.InsertNode(ctx, st, root))
cs := &chainmock.ChainService{Root: headRoot[:], Optimistic: true, ForkChoiceStore: fcs, OptimisticRoots: map[[32]byte]bool{r: false}, FinalizedCheckPoint: finalizedCheckpt}
mf := &testutil.MockStater{BeaconState: st}
o, err := IsOptimistic(ctx, []byte(strconv.Itoa(fieldparams.SlotsPerEpoch*2)), cs, mf, cs, db)
require.NoError(t, err)
assert.Equal(t, false, o)
})
})
}
// prepareForkchoiceState prepares a beacon state with the given data to mock
// insert into forkchoice
func prepareForkchoiceState(
slot primitives.Slot,
blockRoot [32]byte,
parentRoot [32]byte,
payloadHash [32]byte,
justified *eth.Checkpoint,
finalized *eth.Checkpoint,
) (state.BeaconState, [32]byte, error) {
blockHeader := &eth.BeaconBlockHeader{
ParentRoot: parentRoot[:],
}
executionHeader := &enginev1.ExecutionPayloadHeader{
BlockHash: payloadHash[:],
}
base := &eth.BeaconStateBellatrix{
Slot: slot,
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
BlockRoots: make([][]byte, 1),
CurrentJustifiedCheckpoint: justified,
FinalizedCheckpoint: finalized,
LatestExecutionPayloadHeader: executionHeader,
LatestBlockHeader: blockHeader,
}
base.BlockRoots[0] = append(base.BlockRoots[0], blockRoot[:]...)
st, err := state_native.InitializeFromProtoBellatrix(base)
return st, blockRoot, err
}

View File

@@ -0,0 +1,52 @@
load("@prysm//tools/go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = [
"handlers.go",
"server.go",
"structs.go",
],
importpath = "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/rewards",
visibility = ["//visibility:public"],
deps = [
"//beacon-chain/blockchain:go_default_library",
"//beacon-chain/core/altair:go_default_library",
"//beacon-chain/core/blocks:go_default_library",
"//beacon-chain/core/validators:go_default_library",
"//beacon-chain/rpc/lookup:go_default_library",
"//beacon-chain/state/stategen:go_default_library",
"//consensus-types/blocks:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//network:go_default_library",
"//runtime/version:go_default_library",
"@com_github_pkg_errors//:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["handlers_test.go"],
embed = [":go_default_library"],
deps = [
"//beacon-chain/blockchain/testing:go_default_library",
"//beacon-chain/core/altair:go_default_library",
"//beacon-chain/core/signing:go_default_library",
"//beacon-chain/rpc/testutil:go_default_library",
"//beacon-chain/state/stategen/mock: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",
"//crypto/bls:go_default_library",
"//crypto/bls/blst:go_default_library",
"//encoding/bytesutil:go_default_library",
"//network:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//testing/assert:go_default_library",
"//testing/require:go_default_library",
"//testing/util:go_default_library",
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
],
)

View File

@@ -0,0 +1,189 @@
package rewards
import (
"net/http"
"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/validators"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup"
"github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/v4/network"
"github.com/prysmaticlabs/prysm/v4/runtime/version"
)
// BlockRewards is an HTTP handler for Beacon API getBlockRewards.
func (s *Server) BlockRewards(w http.ResponseWriter, r *http.Request) {
segments := strings.Split(r.URL.Path, "/")
blockId := segments[len(segments)-1]
blk, err := s.Blocker.Block(r.Context(), []byte(blockId))
if errJson := handleGetBlockError(blk, err); errJson != nil {
network.WriteError(w, errJson)
return
}
if blk.Version() == version.Phase0 {
errJson := &network.DefaultErrorJson{
Message: "block rewards are not supported for Phase 0 blocks",
Code: http.StatusBadRequest,
}
network.WriteError(w, errJson)
return
}
// We want to run several block processing functions that update the proposer's balance.
// This will allow us to calculate proposer rewards for each operation (atts, slashings etc).
// 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 := &network.DefaultErrorJson{
Message: errors.Wrapf(err, "could not get state").Error(),
Code: http.StatusInternalServerError,
}
network.WriteError(w, errJson)
return
}
proposerIndex := blk.Block().ProposerIndex()
initBalance, err := st.BalanceAtIndex(proposerIndex)
if err != nil {
errJson := &network.DefaultErrorJson{
Message: errors.Wrapf(err, "could not get proposer's balance").Error(),
Code: http.StatusInternalServerError,
}
network.WriteError(w, errJson)
return
}
st, err = altair.ProcessAttestationsNoVerifySignature(r.Context(), st, blk)
if err != nil {
errJson := &network.DefaultErrorJson{
Message: errors.Wrapf(err, "could not get attestation rewards").Error(),
Code: http.StatusInternalServerError,
}
network.WriteError(w, errJson)
return
}
attBalance, err := st.BalanceAtIndex(proposerIndex)
if err != nil {
errJson := &network.DefaultErrorJson{
Message: errors.Wrapf(err, "could not get proposer's balance").Error(),
Code: http.StatusInternalServerError,
}
network.WriteError(w, errJson)
return
}
st, err = coreblocks.ProcessAttesterSlashings(r.Context(), st, blk.Block().Body().AttesterSlashings(), validators.SlashValidator)
if err != nil {
errJson := &network.DefaultErrorJson{
Message: errors.Wrapf(err, "could not get attester slashing rewards").Error(),
Code: http.StatusInternalServerError,
}
network.WriteError(w, errJson)
return
}
attSlashingsBalance, err := st.BalanceAtIndex(proposerIndex)
if err != nil {
errJson := &network.DefaultErrorJson{
Message: errors.Wrapf(err, "could not get proposer's balance").Error(),
Code: http.StatusInternalServerError,
}
network.WriteError(w, errJson)
return
}
st, err = coreblocks.ProcessProposerSlashings(r.Context(), st, blk.Block().Body().ProposerSlashings(), validators.SlashValidator)
if err != nil {
errJson := &network.DefaultErrorJson{
Message: errors.Wrapf(err, "could not get proposer slashing rewards").Error(),
Code: http.StatusInternalServerError,
}
network.WriteError(w, errJson)
return
}
proposerSlashingsBalance, err := st.BalanceAtIndex(proposerIndex)
if err != nil {
errJson := &network.DefaultErrorJson{
Message: errors.Wrapf(err, "could not get proposer's balance").Error(),
Code: http.StatusInternalServerError,
}
network.WriteError(w, errJson)
return
}
sa, err := blk.Block().Body().SyncAggregate()
if err != nil {
errJson := &network.DefaultErrorJson{
Message: errors.Wrapf(err, "could not get sync aggregate").Error(),
Code: http.StatusInternalServerError,
}
network.WriteError(w, errJson)
return
}
var syncCommitteeReward uint64
_, syncCommitteeReward, err = altair.ProcessSyncAggregate(r.Context(), st, sa)
if err != nil {
errJson := &network.DefaultErrorJson{
Message: errors.Wrapf(err, "could not get sync aggregate rewards").Error(),
Code: http.StatusInternalServerError,
}
network.WriteError(w, errJson)
return
}
optimistic, err := s.OptimisticModeFetcher.IsOptimistic(r.Context())
if err != nil {
errJson := &network.DefaultErrorJson{
Message: errors.Wrapf(err, "could not get optimistic mode info").Error(),
Code: http.StatusInternalServerError,
}
network.WriteError(w, errJson)
return
}
blkRoot, err := blk.Block().HashTreeRoot()
if err != nil {
errJson := &network.DefaultErrorJson{
Message: errors.Wrapf(err, "could not get block root").Error(),
Code: http.StatusInternalServerError,
}
network.WriteError(w, errJson)
return
}
response := &BlockRewardsResponse{
Data: &BlockRewards{
ProposerIndex: strconv.FormatUint(uint64(proposerIndex), 10),
Total: strconv.FormatUint(proposerSlashingsBalance-initBalance+syncCommitteeReward, 10),
Attestations: strconv.FormatUint(attBalance-initBalance, 10),
SyncAggregate: strconv.FormatUint(syncCommitteeReward, 10),
ProposerSlashings: strconv.FormatUint(proposerSlashingsBalance-attSlashingsBalance, 10),
AttesterSlashings: strconv.FormatUint(attSlashingsBalance-attBalance, 10),
},
ExecutionOptimistic: optimistic,
Finalized: s.FinalizationFetcher.IsFinalized(r.Context(), blkRoot),
}
network.WriteJson(w, response)
}
func handleGetBlockError(blk interfaces.ReadOnlySignedBeaconBlock, err error) *network.DefaultErrorJson {
if errors.Is(err, lookup.BlockIdParseError{}) {
return &network.DefaultErrorJson{
Message: errors.Wrapf(err, "invalid block ID").Error(),
Code: http.StatusBadRequest,
}
}
if err != nil {
return &network.DefaultErrorJson{
Message: errors.Wrapf(err, "could not get block from block ID").Error(),
Code: http.StatusInternalServerError,
}
}
if err := blocks.BeaconBlockIsNil(blk); err != nil {
return &network.DefaultErrorJson{
Message: errors.Wrapf(err, "could not find requested block").Error(),
Code: http.StatusNotFound,
}
}
return nil
}

View File

@@ -0,0 +1,198 @@
package rewards
import (
"bytes"
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"github.com/prysmaticlabs/go-bitfield"
mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/altair"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/signing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/testutil"
mockstategen "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen/mock"
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"
"github.com/prysmaticlabs/prysm/v4/crypto/bls"
"github.com/prysmaticlabs/prysm/v4/crypto/bls/blst"
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v4/network"
eth "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v4/testing/assert"
"github.com/prysmaticlabs/prysm/v4/testing/require"
"github.com/prysmaticlabs/prysm/v4/testing/util"
)
func TestBlockRewards(t *testing.T) {
valCount := 64
st, err := util.NewBeaconStateAltair()
require.NoError(t, st.SetSlot(1))
require.NoError(t, err)
validators := make([]*eth.Validator, 0, valCount)
balances := make([]uint64, 0, valCount)
secretKeys := make([]bls.SecretKey, 0, valCount)
for i := 0; i < valCount; i++ {
blsKey, err := bls.RandKey()
require.NoError(t, err)
secretKeys = append(secretKeys, blsKey)
validators = append(validators, &eth.Validator{
PublicKey: blsKey.PublicKey().Marshal(),
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch,
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
})
balances = append(balances, params.BeaconConfig().MaxEffectiveBalance)
}
require.NoError(t, st.SetValidators(validators))
require.NoError(t, st.SetBalances(balances))
require.NoError(t, st.SetCurrentParticipationBits(make([]byte, valCount)))
syncCommittee, err := altair.NextSyncCommittee(context.Background(), st)
require.NoError(t, err)
require.NoError(t, st.SetCurrentSyncCommittee(syncCommittee))
slot0bRoot := bytesutil.PadTo([]byte("slot0root"), 32)
bRoots := make([][]byte, fieldparams.BlockRootsLength)
bRoots[0] = slot0bRoot
require.NoError(t, st.SetBlockRoots(bRoots))
b := util.HydrateSignedBeaconBlockAltair(util.NewBeaconBlockAltair())
b.Block.Slot = 2
// we have to set the proposer index to the value that will be randomly chosen (fortunately it's deterministic)
b.Block.ProposerIndex = 12
b.Block.Body.Attestations = []*eth.Attestation{
{
AggregationBits: bitfield.Bitlist{0b00000111},
Data: util.HydrateAttestationData(&eth.AttestationData{}),
Signature: make([]byte, fieldparams.BLSSignatureLength),
},
{
AggregationBits: bitfield.Bitlist{0b00000111},
Data: util.HydrateAttestationData(&eth.AttestationData{}),
Signature: make([]byte, fieldparams.BLSSignatureLength),
},
}
attData1 := util.HydrateAttestationData(&eth.AttestationData{BeaconBlockRoot: bytesutil.PadTo([]byte("root1"), 32)})
attData2 := util.HydrateAttestationData(&eth.AttestationData{BeaconBlockRoot: bytesutil.PadTo([]byte("root2"), 32)})
domain, err := signing.Domain(st.Fork(), 0, params.BeaconConfig().DomainBeaconAttester, st.GenesisValidatorsRoot())
require.NoError(t, err)
sigRoot1, err := signing.ComputeSigningRoot(attData1, domain)
require.NoError(t, err)
sigRoot2, err := signing.ComputeSigningRoot(attData2, domain)
require.NoError(t, err)
b.Block.Body.AttesterSlashings = []*eth.AttesterSlashing{
{
Attestation_1: &eth.IndexedAttestation{
AttestingIndices: []uint64{0},
Data: attData1,
Signature: secretKeys[0].Sign(sigRoot1[:]).Marshal(),
},
Attestation_2: &eth.IndexedAttestation{
AttestingIndices: []uint64{0},
Data: attData2,
Signature: secretKeys[0].Sign(sigRoot2[:]).Marshal(),
},
},
}
header1 := &eth.BeaconBlockHeader{
Slot: 0,
ProposerIndex: 1,
ParentRoot: bytesutil.PadTo([]byte("root1"), 32),
StateRoot: bytesutil.PadTo([]byte("root1"), 32),
BodyRoot: bytesutil.PadTo([]byte("root1"), 32),
}
header2 := &eth.BeaconBlockHeader{
Slot: 0,
ProposerIndex: 1,
ParentRoot: bytesutil.PadTo([]byte("root2"), 32),
StateRoot: bytesutil.PadTo([]byte("root2"), 32),
BodyRoot: bytesutil.PadTo([]byte("root2"), 32),
}
domain, err = signing.Domain(st.Fork(), 0, params.BeaconConfig().DomainBeaconProposer, st.GenesisValidatorsRoot())
require.NoError(t, err)
sigRoot1, err = signing.ComputeSigningRoot(header1, domain)
require.NoError(t, err)
sigRoot2, err = signing.ComputeSigningRoot(header2, domain)
require.NoError(t, err)
b.Block.Body.ProposerSlashings = []*eth.ProposerSlashing{
{
Header_1: &eth.SignedBeaconBlockHeader{
Header: header1,
Signature: secretKeys[1].Sign(sigRoot1[:]).Marshal(),
},
Header_2: &eth.SignedBeaconBlockHeader{
Header: header2,
Signature: secretKeys[1].Sign(sigRoot2[:]).Marshal(),
},
},
}
scBits := bitfield.NewBitvector512()
scBits.SetBitAt(10, true)
scBits.SetBitAt(100, true)
domain, err = signing.Domain(st.Fork(), 0, params.BeaconConfig().DomainSyncCommittee, st.GenesisValidatorsRoot())
require.NoError(t, err)
sszBytes := primitives.SSZBytes(slot0bRoot)
r, err := signing.ComputeSigningRoot(&sszBytes, domain)
require.NoError(t, err)
// Bits set in sync committee bits determine which validators will be treated as participating in sync committee.
// These validators have to sign the message.
sig1, err := blst.SignatureFromBytes(secretKeys[47].Sign(r[:]).Marshal())
require.NoError(t, err)
sig2, err := blst.SignatureFromBytes(secretKeys[19].Sign(r[:]).Marshal())
require.NoError(t, err)
aggSig := bls.AggregateSignatures([]bls.Signature{sig1, sig2}).Marshal()
b.Block.Body.SyncAggregate = &eth.SyncAggregate{SyncCommitteeBits: scBits, SyncCommitteeSignature: aggSig}
sbb, err := blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
phase0block, err := blocks.NewSignedBeaconBlock(util.NewBeaconBlock())
require.NoError(t, err)
mockChainService := &mock.ChainService{Optimistic: true}
s := &Server{
Blocker: &testutil.MockBlocker{SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{
0: phase0block,
2: sbb,
}},
OptimisticModeFetcher: mockChainService,
FinalizationFetcher: mockChainService,
ReplayerBuilder: mockstategen.NewMockReplayerBuilder(mockstategen.WithMockState(st)),
}
t.Run("ok", func(t *testing.T) {
url := "http://only.the.slot.number.at.the.end.is.important/2"
request := httptest.NewRequest("GET", url, nil)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.BlockRewards(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
resp := &BlockRewardsResponse{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
assert.Equal(t, "12", resp.Data.ProposerIndex)
assert.Equal(t, "125089490", resp.Data.Total)
assert.Equal(t, "89442", resp.Data.Attestations)
assert.Equal(t, "48", resp.Data.SyncAggregate)
assert.Equal(t, "62500000", resp.Data.AttesterSlashings)
assert.Equal(t, "62500000", resp.Data.ProposerSlashings)
assert.Equal(t, true, resp.ExecutionOptimistic)
assert.Equal(t, false, resp.Finalized)
})
t.Run("phase 0", func(t *testing.T) {
url := "http://only.the.slot.number.at.the.end.is.important/0"
request := httptest.NewRequest("GET", url, nil)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.BlockRewards(writer, request)
assert.Equal(t, http.StatusBadRequest, writer.Code)
e := &network.DefaultErrorJson{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), e))
assert.Equal(t, http.StatusBadRequest, e.Code)
assert.Equal(t, "block rewards are not supported for Phase 0 blocks", e.Message)
})
}

View File

@@ -0,0 +1,14 @@
package rewards
import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen"
)
type Server struct {
Blocker lookup.Blocker
OptimisticModeFetcher blockchain.OptimisticModeFetcher
FinalizationFetcher blockchain.FinalizationFetcher
ReplayerBuilder stategen.ReplayerBuilder
}

View File

@@ -0,0 +1,16 @@
package rewards
type BlockRewardsResponse struct {
Data *BlockRewards `json:"data"`
ExecutionOptimistic bool `json:"execution_optimistic"`
Finalized bool `json:"finalized"`
}
type BlockRewards struct {
ProposerIndex string `json:"proposer_index"`
Total string `json:"total"`
Attestations string `json:"attestations"`
SyncAggregate string `json:"sync_aggregate"`
ProposerSlashings string `json:"proposer_slashings"`
AttesterSlashings string `json:"attester_slashings"`
}

View File

@@ -13,13 +13,14 @@ go_library(
"//beacon-chain/builder:go_default_library",
"//beacon-chain/cache:go_default_library",
"//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/db:go_default_library",
"//beacon-chain/db/kv:go_default_library",
"//beacon-chain/operations/attestations:go_default_library",
"//beacon-chain/operations/synccommittee:go_default_library",
"//beacon-chain/p2p:go_default_library",
"//beacon-chain/rpc/eth/helpers:go_default_library",
"//beacon-chain/rpc/lookup:go_default_library",
"//beacon-chain/rpc/prysm/v1alpha1/validator:go_default_library",
"//beacon-chain/rpc/statefetcher:go_default_library",
"//beacon-chain/state:go_default_library",
"//beacon-chain/state/state-native:go_default_library",
"//beacon-chain/sync:go_default_library",

View File

@@ -3,11 +3,12 @@ package validator
import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/cache"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/db"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/attestations"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/synccommittee"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup"
v1alpha1validator "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/prysm/v1alpha1/validator"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/statefetcher"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/sync"
)
@@ -15,15 +16,16 @@ import (
// providing RPC endpoints intended for validator clients.
type Server struct {
HeadFetcher blockchain.HeadFetcher
HeadUpdater blockchain.HeadUpdater
TimeFetcher blockchain.TimeFetcher
SyncChecker sync.Checker
AttestationsPool attestations.Pool
PeerManager p2p.PeerManager
Broadcaster p2p.Broadcaster
StateFetcher statefetcher.Fetcher
Stater lookup.Stater
OptimisticModeFetcher blockchain.OptimisticModeFetcher
SyncCommitteePool synccommittee.Pool
V1Alpha1Server *v1alpha1validator.Server
ProposerSlotIndexCache *cache.ProposerPayloadIDsCache
ChainInfoFetcher blockchain.ChainInfoFetcher
BeaconDB db.ReadOnlyDatabase
}

View File

@@ -70,7 +70,7 @@ func (vs *Server) GetAttesterDuties(ctx context.Context, req *ethpbv1.AttesterDu
return nil, status.Errorf(codes.Internal, "Could not get start slot from epoch %d: %v", req.Epoch, err)
}
s, err := vs.StateFetcher.StateBySlot(ctx, startSlot)
s, err := vs.Stater.StateBySlot(ctx, startSlot)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get state: %v", err)
}
@@ -159,7 +159,7 @@ func (vs *Server) GetProposerDuties(ctx context.Context, req *ethpbv1.ProposerDu
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get start slot from epoch %d: %v", req.Epoch, err)
}
s, err := vs.StateFetcher.StateBySlot(ctx, startSlot)
s, err := vs.Stater.StateBySlot(ctx, startSlot)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get state: %v", err)
}
@@ -243,7 +243,7 @@ func (vs *Server) GetSyncCommitteeDuties(ctx context.Context, req *ethpbv2.SyncC
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get sync committee slot: %v", err)
}
st, err := vs.StateFetcher.State(ctx, []byte(strconv.FormatUint(uint64(slot), 10)))
st, err := vs.Stater.State(ctx, []byte(strconv.FormatUint(uint64(slot), 10)))
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get sync committee state: %v", err)
}
@@ -278,7 +278,14 @@ func (vs *Server) GetSyncCommitteeDuties(ctx context.Context, req *ethpbv2.SyncC
return nil, status.Errorf(codes.Internal, "Could not get duties: %v", err)
}
isOptimistic, err := rpchelpers.IsOptimistic(ctx, st, vs.OptimisticModeFetcher)
isOptimistic, err := rpchelpers.IsOptimistic(
ctx,
[]byte(strconv.FormatUint(uint64(slot), 10)),
vs.OptimisticModeFetcher,
vs.Stater,
vs.ChainInfoFetcher,
vs.BeaconDB,
)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not check if slot's block is optimistic: %v", err)
}
@@ -1074,7 +1081,7 @@ func (vs *Server) GetLiveness(ctx context.Context, req *ethpbv2.GetLivenessReque
if err != nil {
return nil, status.Error(codes.Internal, "Could not get requested epoch's end slot")
}
st, err = vs.StateFetcher.StateBySlot(ctx, epochEnd)
st, err = vs.Stater.StateBySlot(ctx, epochEnd)
if err != nil {
return nil, status.Error(codes.Internal, "Could not get slot for requested epoch")
}

View File

@@ -93,7 +93,7 @@ func TestGetAttesterDuties(t *testing.T) {
State: bs, Root: genesisRoot[:], Slot: &chainSlot,
}
vs := &Server{
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
StatesBySlot: map[primitives.Slot]state.BeaconState{
0: bs,
params.BeaconConfig().SlotsPerEpoch: nextEpochState,
@@ -198,7 +198,7 @@ func TestGetAttesterDuties(t *testing.T) {
State: bs, Root: genesisRoot[:], Slot: &chainSlot, Optimistic: true,
}
vs := &Server{
StateFetcher: &testutil.MockFetcher{StatesBySlot: map[primitives.Slot]state.BeaconState{0: bs}},
Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{0: bs}},
TimeFetcher: chain,
OptimisticModeFetcher: chain,
SyncChecker: &mockSync.Sync{IsSyncing: false},
@@ -258,7 +258,7 @@ func TestGetProposerDuties(t *testing.T) {
State: bs, Root: genesisRoot[:], Slot: &chainSlot,
}
vs := &Server{
StateFetcher: &testutil.MockFetcher{StatesBySlot: map[primitives.Slot]state.BeaconState{0: bs}},
Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{0: bs}},
HeadFetcher: chain,
TimeFetcher: chain,
OptimisticModeFetcher: chain,
@@ -297,7 +297,7 @@ func TestGetProposerDuties(t *testing.T) {
State: bs, Root: genesisRoot[:], Slot: &chainSlot,
}
vs := &Server{
StateFetcher: &testutil.MockFetcher{StatesBySlot: map[primitives.Slot]state.BeaconState{0: bs}},
Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{0: bs}},
HeadFetcher: chain,
TimeFetcher: chain,
OptimisticModeFetcher: chain,
@@ -337,7 +337,7 @@ func TestGetProposerDuties(t *testing.T) {
State: bs, Root: genesisRoot[:], Slot: &chainSlot,
}
vs := &Server{
StateFetcher: &testutil.MockFetcher{StatesBySlot: map[primitives.Slot]state.BeaconState{params.BeaconConfig().SlotsPerEpoch: bs}},
Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{params.BeaconConfig().SlotsPerEpoch: bs}},
HeadFetcher: chain,
TimeFetcher: chain,
OptimisticModeFetcher: chain,
@@ -377,7 +377,7 @@ func TestGetProposerDuties(t *testing.T) {
State: bs, Root: genesisRoot[:], Slot: &chainSlot,
}
vs := &Server{
StateFetcher: &testutil.MockFetcher{StatesBySlot: map[primitives.Slot]state.BeaconState{0: bs}},
Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{0: bs}},
HeadFetcher: chain,
TimeFetcher: chain,
OptimisticModeFetcher: chain,
@@ -414,7 +414,7 @@ func TestGetProposerDuties(t *testing.T) {
State: bs, Root: genesisRoot[:], Slot: &chainSlot, Optimistic: true,
}
vs := &Server{
StateFetcher: &testutil.MockFetcher{StatesBySlot: map[primitives.Slot]state.BeaconState{0: bs}},
Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{0: bs}},
HeadFetcher: chain,
TimeFetcher: chain,
OptimisticModeFetcher: chain,
@@ -466,11 +466,10 @@ func TestGetSyncCommitteeDuties(t *testing.T) {
}
require.NoError(t, st.SetNextSyncCommittee(nextCommittee))
db := dbutil.SetupDB(t)
mockChainService := &mockChain.ChainService{Genesis: genesisTime}
vs := &Server{
StateFetcher: &testutil.MockFetcher{BeaconState: st},
Stater: &testutil.MockStater{BeaconState: st},
SyncChecker: &mockSync.Sync{IsSyncing: false},
TimeFetcher: mockChainService,
HeadFetcher: mockChainService,
@@ -612,7 +611,7 @@ func TestGetSyncCommitteeDuties(t *testing.T) {
}
mockChainService := &mockChain.ChainService{Genesis: genesisTime, Slot: &newSyncPeriodStartSlot}
vs := &Server{
StateFetcher: &testutil.MockFetcher{BeaconState: stateFetchFn(newSyncPeriodStartSlot)},
Stater: &testutil.MockStater{BeaconState: stateFetchFn(newSyncPeriodStartSlot)},
SyncChecker: &mockSync.Sync{IsSyncing: false},
TimeFetcher: mockChainService,
HeadFetcher: mockChainService,
@@ -636,6 +635,10 @@ func TestGetSyncCommitteeDuties(t *testing.T) {
})
t.Run("execution optimistic", func(t *testing.T) {
db := dbutil.SetupDB(t)
require.NoError(t, db.SaveStateSummary(ctx, &ethpbalpha.StateSummary{Slot: 0, Root: []byte("root")}))
require.NoError(t, db.SaveLastValidatedCheckpoint(ctx, &ethpbalpha.Checkpoint{Epoch: 0, Root: []byte("root")}))
parentRoot := [32]byte{'a'}
blk := util.NewBeaconBlock()
blk.Block.ParentRoot = parentRoot[:]
@@ -644,16 +647,34 @@ func TestGetSyncCommitteeDuties(t *testing.T) {
util.SaveBlock(t, ctx, db, blk)
require.NoError(t, db.SaveGenesisBlockRoot(ctx, root))
mockChainService := &mockChain.ChainService{Genesis: genesisTime, Optimistic: true}
slot, err := slots.EpochStart(1)
require.NoError(t, err)
state, err := util.NewBeaconStateBellatrix()
require.NoError(t, err)
require.NoError(t, state.SetSlot(slot))
mockChainService := &mockChain.ChainService{
Genesis: genesisTime,
Optimistic: true,
Slot: &slot,
FinalizedCheckPoint: &ethpbalpha.Checkpoint{
Root: root[:],
Epoch: 1,
},
State: state,
}
vs := &Server{
StateFetcher: &testutil.MockFetcher{BeaconState: st},
Stater: &testutil.MockStater{BeaconState: st},
SyncChecker: &mockSync.Sync{IsSyncing: false},
TimeFetcher: mockChainService,
HeadFetcher: mockChainService,
OptimisticModeFetcher: mockChainService,
ChainInfoFetcher: mockChainService,
BeaconDB: db,
}
req := &ethpbv2.SyncCommitteeDutiesRequest{
Epoch: 0,
Epoch: 1,
Index: []primitives.ValidatorIndex{1},
}
resp, err := vs.GetSyncCommitteeDuties(ctx, req)
@@ -702,8 +723,8 @@ func TestProduceBlockV2(t *testing.T) {
HeadFetcher: mockChainService,
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockReceiver: mockChainService,
HeadUpdater: mockChainService,
ForkFetcher: mockChainService,
ForkchoiceFetcher: mockChainService,
ChainStartFetcher: mockExecutionChain,
Eth1InfoFetcher: mockExecutionChain,
Eth1BlockFetcher: mockExecutionChain,
@@ -814,8 +835,8 @@ func TestProduceBlockV2(t *testing.T) {
HeadFetcher: mockChainService,
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockReceiver: mockChainService,
HeadUpdater: mockChainService,
ForkFetcher: mockChainService,
ForkchoiceFetcher: mockChainService,
ChainStartFetcher: mockExecutionChain,
Eth1InfoFetcher: mockExecutionChain,
Eth1BlockFetcher: mockExecutionChain,
@@ -1012,10 +1033,11 @@ func TestProduceBlockV2(t *testing.T) {
TimeFetcher: mockChainService,
HeadFetcher: mockChainService,
OptimisticModeFetcher: mockChainService,
FinalizationFetcher: mockChainService,
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockReceiver: mockChainService,
HeadUpdater: mockChainService,
ForkFetcher: mockChainService,
ForkchoiceFetcher: mockChainService,
ChainStartFetcher: mockExecutionChain,
Eth1InfoFetcher: mockExecutionChain,
Eth1BlockFetcher: mockExecutionChain,
@@ -1257,8 +1279,9 @@ func TestProduceBlockV2(t *testing.T) {
OptimisticModeFetcher: mockChainService,
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockReceiver: mockChainService,
HeadUpdater: mockChainService,
ForkFetcher: mockChainService,
ForkchoiceFetcher: mockChainService,
FinalizationFetcher: mockChainService,
ChainStartFetcher: mockExecutionChain,
Eth1InfoFetcher: mockExecutionChain,
Eth1BlockFetcher: mockExecutionChain,
@@ -1392,19 +1415,21 @@ func TestProduceBlockV2SSZ(t *testing.T) {
mockChainService := &mockChain.ChainService{State: bs, Root: parentRoot[:], ForkChoiceStore: doublylinkedtree.New()}
v1Alpha1Server := &v1alpha1validator.Server{
HeadFetcher: mockChainService,
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockReceiver: mockChainService,
HeadUpdater: mockChainService,
ForkFetcher: mockChainService,
ChainStartFetcher: &mockExecution.Chain{},
Eth1InfoFetcher: &mockExecution.Chain{},
Eth1BlockFetcher: &mockExecution.Chain{},
MockEth1Votes: true,
AttPool: attestations.NewPool(),
SlashingsPool: slashings.NewPool(),
ExitPool: voluntaryexits.NewPool(),
StateGen: stategen.New(db, doublylinkedtree.New()),
HeadFetcher: mockChainService,
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockReceiver: mockChainService,
TimeFetcher: mockChainService,
ForkFetcher: mockChainService,
ForkchoiceFetcher: mockChainService,
FinalizationFetcher: mockChainService,
ChainStartFetcher: &mockExecution.Chain{},
Eth1InfoFetcher: &mockExecution.Chain{},
Eth1BlockFetcher: &mockExecution.Chain{},
MockEth1Votes: true,
AttPool: attestations.NewPool(),
SlashingsPool: slashings.NewPool(),
ExitPool: voluntaryexits.NewPool(),
StateGen: stategen.New(db, doublylinkedtree.New()),
}
proposerSlashings := make([]*ethpbalpha.ProposerSlashing, 1)
@@ -1558,8 +1583,9 @@ func TestProduceBlockV2SSZ(t *testing.T) {
HeadFetcher: mockChainService,
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockReceiver: mockChainService,
HeadUpdater: mockChainService,
TimeFetcher: mockChainService,
ForkFetcher: mockChainService,
ForkchoiceFetcher: mockChainService,
ChainStartFetcher: &mockExecution.Chain{},
Eth1InfoFetcher: &mockExecution.Chain{},
Eth1BlockFetcher: &mockExecution.Chain{},
@@ -1764,8 +1790,8 @@ func TestProduceBlockV2SSZ(t *testing.T) {
OptimisticModeFetcher: mockChainService,
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockReceiver: mockChainService,
HeadUpdater: mockChainService,
ForkFetcher: mockChainService,
ForkchoiceFetcher: mockChainService,
ChainStartFetcher: &mockExecution.Chain{},
Eth1InfoFetcher: &mockExecution.Chain{},
Eth1BlockFetcher: &mockExecution.Chain{},
@@ -2008,8 +2034,9 @@ func TestProduceBlockV2SSZ(t *testing.T) {
OptimisticModeFetcher: mockChainService,
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockReceiver: mockChainService,
HeadUpdater: mockChainService,
ForkFetcher: mockChainService,
ForkchoiceFetcher: mockChainService,
FinalizationFetcher: mockChainService,
ChainStartFetcher: &mockExecution.Chain{},
Eth1InfoFetcher: &mockExecution.Chain{},
Eth1BlockFetcher: &mockExecution.Chain{},
@@ -2239,8 +2266,9 @@ func TestProduceBlindedBlock(t *testing.T) {
HeadFetcher: mockChainService,
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockReceiver: mockChainService,
HeadUpdater: mockChainService,
ForkFetcher: mockChainService,
TimeFetcher: mockChainService,
ForkchoiceFetcher: mockChainService,
ChainStartFetcher: &mockExecution.Chain{},
Eth1InfoFetcher: &mockExecution.Chain{},
Eth1BlockFetcher: &mockExecution.Chain{},
@@ -2345,8 +2373,9 @@ func TestProduceBlindedBlock(t *testing.T) {
HeadFetcher: mockChainService,
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockReceiver: mockChainService,
HeadUpdater: mockChainService,
ForkFetcher: mockChainService,
TimeFetcher: mockChainService,
ForkchoiceFetcher: mockChainService,
ChainStartFetcher: &mockExecution.Chain{},
Eth1InfoFetcher: &mockExecution.Chain{},
Eth1BlockFetcher: &mockExecution.Chain{},
@@ -2536,12 +2565,12 @@ func TestProduceBlindedBlock(t *testing.T) {
v1Alpha1Server := &v1alpha1validator.Server{
BeaconDB: db,
ForkFetcher: mockChainService,
ForkchoiceFetcher: mockChainService,
TimeFetcher: mockChainService,
HeadFetcher: mockChainService,
OptimisticModeFetcher: mockChainService,
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockReceiver: mockChainService,
HeadUpdater: mockChainService,
ChainStartFetcher: &mockExecution.Chain{GenesisState: beaconState},
Eth1InfoFetcher: &mockExecution.Chain{},
Eth1BlockFetcher: &mockExecution.Chain{},
@@ -2722,6 +2751,7 @@ func TestProduceBlindedBlock(t *testing.T) {
require.NoError(t, err)
wr, err := ssz.WithdrawalSliceRoot(wds, fieldparams.MaxWithdrawalsPerPayload)
require.NoError(t, err)
v := big.NewInt(1e9) // minimal 1 gwei
bid := &ethpbalpha.BuilderBidCapella{
Header: &enginev1.ExecutionPayloadHeaderCapella{
ParentHash: make([]byte, fieldparams.RootLength),
@@ -2738,7 +2768,7 @@ func TestProduceBlindedBlock(t *testing.T) {
WithdrawalsRoot: wr[:],
},
Pubkey: sk.PublicKey().Marshal(),
Value: bytesutil.PadTo([]byte{1, 2, 3}, 32),
Value: bytesutil.PadTo(bytesutil.ReverseByteOrder(v.Bytes()), 32),
}
d := params.BeaconConfig().DomainApplicationBuilder
domain, err := signing.ComputeDomain(d, nil, nil)
@@ -2759,12 +2789,12 @@ func TestProduceBlindedBlock(t *testing.T) {
ExecutionEngineCaller: &mockExecution.EngineClient{PayloadIDBytes: id, ExecutionPayloadCapella: &enginev1.ExecutionPayloadCapella{BlockNumber: 1, Withdrawals: wds}, BlockValue: big.NewInt(0)},
BeaconDB: db,
ForkFetcher: mockChainService,
ForkchoiceFetcher: mockChainService,
TimeFetcher: mockChainService,
HeadFetcher: mockChainService,
OptimisticModeFetcher: mockChainService,
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockReceiver: mockChainService,
HeadUpdater: mockChainService,
ChainStartFetcher: &mockExecution.Chain{},
Eth1InfoFetcher: &mockExecution.Chain{},
Eth1BlockFetcher: &mockExecution.Chain{},
@@ -2909,8 +2939,9 @@ func TestProduceBlindedBlockSSZ(t *testing.T) {
HeadFetcher: mockChainService,
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockReceiver: mockChainService,
HeadUpdater: mockChainService,
TimeFetcher: mockChainService,
ForkFetcher: mockChainService,
ForkchoiceFetcher: mockChainService,
ChainStartFetcher: &mockExecution.Chain{},
Eth1InfoFetcher: &mockExecution.Chain{},
Eth1BlockFetcher: &mockExecution.Chain{},
@@ -2919,6 +2950,7 @@ func TestProduceBlindedBlockSSZ(t *testing.T) {
SlashingsPool: slashings.NewPool(),
ExitPool: voluntaryexits.NewPool(),
StateGen: stategen.New(db, doublylinkedtree.New()),
BlockBuilder: &builderTest.MockBuilderService{HasConfigured: true},
}
proposerSlashings := make([]*ethpbalpha.ProposerSlashing, 1)
@@ -3072,8 +3104,9 @@ func TestProduceBlindedBlockSSZ(t *testing.T) {
HeadFetcher: mockChainService,
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockReceiver: &mockChain.ChainService{},
HeadUpdater: mockChainService,
TimeFetcher: mockChainService,
ForkFetcher: mockChainService,
ForkchoiceFetcher: mockChainService,
ChainStartFetcher: &mockExecution.Chain{},
Eth1InfoFetcher: &mockExecution.Chain{},
Eth1BlockFetcher: &mockExecution.Chain{},
@@ -3083,6 +3116,7 @@ func TestProduceBlindedBlockSSZ(t *testing.T) {
ExitPool: voluntaryexits.NewPool(),
StateGen: stategen.New(db, doublylinkedtree.New()),
SyncCommitteePool: synccommittee.NewStore(),
BlockBuilder: &builderTest.MockBuilderService{HasConfigured: true},
}
proposerSlashings := make([]*ethpbalpha.ProposerSlashing, 1)
@@ -3278,8 +3312,8 @@ func TestProduceBlindedBlockSSZ(t *testing.T) {
OptimisticModeFetcher: mockChainService,
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockReceiver: mockChainService,
HeadUpdater: mockChainService,
ForkFetcher: mockChainService,
ForkchoiceFetcher: mockChainService,
ChainStartFetcher: &mockExecution.Chain{},
Eth1InfoFetcher: &mockExecution.Chain{},
Eth1BlockFetcher: &mockExecution.Chain{},
@@ -3290,6 +3324,7 @@ func TestProduceBlindedBlockSSZ(t *testing.T) {
StateGen: stategen.New(db, doublylinkedtree.New()),
SyncCommitteePool: synccommittee.NewStore(),
ProposerSlotIndexCache: cache.NewProposerPayloadIDsCache(),
BlockBuilder: &builderTest.MockBuilderService{HasConfigured: true},
}
proposerSlashings := make([]*ethpbalpha.ProposerSlashing, 1)
@@ -3516,8 +3551,9 @@ func TestProduceBlindedBlockSSZ(t *testing.T) {
OptimisticModeFetcher: &mockChain.ChainService{},
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockReceiver: mockChainService,
HeadUpdater: mockChainService,
ForkFetcher: mockChainService,
ForkchoiceFetcher: mockChainService,
FinalizationFetcher: mockChainService,
ChainStartFetcher: &mockExecution.Chain{},
Eth1InfoFetcher: &mockExecution.Chain{},
Eth1BlockFetcher: &mockExecution.Chain{},
@@ -4994,7 +5030,7 @@ func TestGetLiveness(t *testing.T) {
server := &Server{
HeadFetcher: &mockChain.ChainService{State: headSt},
StateFetcher: &testutil.MockFetcher{
Stater: &testutil.MockStater{
// We configure states for last slots of an epoch
StatesBySlot: map[primitives.Slot]state.BeaconState{
params.BeaconConfig().SlotsPerEpoch - 1: oldSt,

View File

@@ -2,9 +2,12 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = ["fetcher.go"],
importpath = "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/statefetcher",
visibility = ["//beacon-chain:__subpackages__"],
srcs = [
"blocker.go",
"stater.go",
],
importpath = "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup",
visibility = ["//visibility:public"],
deps = [
"//beacon-chain/blockchain:go_default_library",
"//beacon-chain/db:go_default_library",
@@ -12,6 +15,7 @@ go_library(
"//beacon-chain/state/stategen: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",
"//encoding/bytesutil:go_default_library",
"//time/slots:go_default_library",
@@ -22,11 +26,15 @@ go_library(
go_test(
name = "go_default_test",
srcs = ["fetcher_test.go"],
srcs = [
"blocker_test.go",
"stater_test.go",
],
embed = [":go_default_library"],
deps = [
"//beacon-chain/blockchain/testing:go_default_library",
"//beacon-chain/db/testing:go_default_library",
"//beacon-chain/rpc/testutil:go_default_library",
"//beacon-chain/state/state-native:go_default_library",
"//beacon-chain/state/stategen:go_default_library",
"//beacon-chain/state/stategen/mock:go_default_library",

View File

@@ -0,0 +1,108 @@
package lookup
import (
"context"
"strconv"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/db"
"github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
)
// BlockIdParseError represents an error scenario where a block ID could not be parsed.
type BlockIdParseError struct {
message string
}
// NewBlockIdParseError creates a new error instance.
func NewBlockIdParseError(reason error) BlockIdParseError {
return BlockIdParseError{
message: errors.Wrapf(reason, "could not parse block ID").Error(),
}
}
// Error returns the underlying error message.
func (e BlockIdParseError) Error() string {
return e.message
}
// Blocker is responsible for retrieving blocks.
type Blocker interface {
Block(ctx context.Context, id []byte) (interfaces.ReadOnlySignedBeaconBlock, error)
}
// BeaconDbBlocker is an implementation of Blocker. It retrieves blocks from the beacon chain database.
type BeaconDbBlocker struct {
BeaconDB db.ReadOnlyDatabase
ChainInfoFetcher blockchain.ChainInfoFetcher
}
// Block returns the beacon block for a given identifier. The identifier can be one of:
// - "head" (canonical head in node's view)
// - "genesis"
// - "finalized"
// - "justified"
// - <slot>
// - <hex encoded block root with '0x' prefix>
func (p *BeaconDbBlocker) Block(ctx context.Context, id []byte) (interfaces.ReadOnlySignedBeaconBlock, error) {
var err error
var blk interfaces.ReadOnlySignedBeaconBlock
switch string(id) {
case "head":
blk, err = p.ChainInfoFetcher.HeadBlock(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not retrieve head block")
}
case "finalized":
finalized := p.ChainInfoFetcher.FinalizedCheckpt()
finalizedRoot := bytesutil.ToBytes32(finalized.Root)
blk, err = p.BeaconDB.Block(ctx, finalizedRoot)
if err != nil {
return nil, errors.New("could not get finalized block from db")
}
case "genesis":
blk, err = p.BeaconDB.GenesisBlock(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not retrieve genesis block")
}
default:
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")
}
} else {
slot, err := strconv.ParseUint(string(id), 10, 64)
if err != nil {
e := NewBlockIdParseError(err)
return nil, &e
}
blks, err := p.BeaconDB.BlocksBySlot(ctx, primitives.Slot(slot))
if err != nil {
return nil, errors.Wrapf(err, "could not retrieve blocks for slot %d", slot)
}
_, roots, err := p.BeaconDB.BlockRootsBySlot(ctx, primitives.Slot(slot))
if err != nil {
return nil, errors.Wrapf(err, "could not retrieve block roots for slot %d", slot)
}
numBlks := len(blks)
if numBlks == 0 {
return nil, nil
}
for i, b := range blks {
canonical, err := p.ChainInfoFetcher.IsCanonical(ctx, roots[i])
if err != nil {
return nil, errors.Wrapf(err, "could not determine if block root is canonical")
}
if canonical {
blk = b
break
}
}
}
}
return blk, nil
}

View File

@@ -0,0 +1,144 @@
package lookup
import (
"context"
"fmt"
"reflect"
"testing"
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"
"github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
ethpbalpha "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v4/testing/assert"
"github.com/prysmaticlabs/prysm/v4/testing/require"
"github.com/prysmaticlabs/prysm/v4/testing/util"
)
func TestGetBlock(t *testing.T) {
beaconDB := dbtesting.SetupDB(t)
ctx := context.Background()
genBlk, blkContainers := testutil.FillDBWithBlocks(ctx, t, beaconDB)
canonicalRoots := make(map[[32]byte]bool)
for _, bContr := range blkContainers {
canonicalRoots[bytesutil.ToBytes32(bContr.BlockRoot)] = true
}
headBlock := blkContainers[len(blkContainers)-1]
nextSlot := headBlock.GetPhase0Block().Block.Slot + 1
b2 := util.NewBeaconBlock()
b2.Block.Slot = 30
b2.Block.ParentRoot = bytesutil.PadTo([]byte{1}, 32)
util.SaveBlock(t, ctx, beaconDB, b2)
b3 := util.NewBeaconBlock()
b3.Block.Slot = 30
b3.Block.ParentRoot = bytesutil.PadTo([]byte{4}, 32)
util.SaveBlock(t, ctx, beaconDB, b3)
b4 := util.NewBeaconBlock()
b4.Block.Slot = nextSlot
b4.Block.ParentRoot = bytesutil.PadTo([]byte{8}, 32)
util.SaveBlock(t, ctx, beaconDB, b4)
wsb, err := blocks.NewSignedBeaconBlock(headBlock.Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block)
require.NoError(t, err)
fetcher := &BeaconDbBlocker{
BeaconDB: beaconDB,
ChainInfoFetcher: &mock.ChainService{
DB: beaconDB,
Block: wsb,
Root: headBlock.BlockRoot,
FinalizedCheckPoint: &ethpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot},
CanonicalRoots: canonicalRoots,
},
}
root, err := genBlk.Block.HashTreeRoot()
require.NoError(t, err)
tests := []struct {
name string
blockID []byte
want *ethpbalpha.SignedBeaconBlock
wantErr bool
}{
{
name: "slot",
blockID: []byte("30"),
want: blkContainers[30].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block,
},
{
name: "bad formatting",
blockID: []byte("3bad0"),
wantErr: true,
},
{
name: "canonical",
blockID: []byte("30"),
want: blkContainers[30].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block,
},
{
name: "non canonical",
blockID: []byte(fmt.Sprintf("%d", nextSlot)),
want: nil,
},
{
name: "head",
blockID: []byte("head"),
want: headBlock.Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block,
},
{
name: "finalized",
blockID: []byte("finalized"),
want: blkContainers[64].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block,
},
{
name: "genesis",
blockID: []byte("genesis"),
want: genBlk,
},
{
name: "genesis root",
blockID: root[:],
want: genBlk,
},
{
name: "root",
blockID: blkContainers[20].BlockRoot,
want: blkContainers[20].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block,
},
{
name: "non-existent root",
blockID: bytesutil.PadTo([]byte("hi there"), 32),
want: nil,
},
{
name: "no block",
blockID: []byte("105"),
want: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := fetcher.Block(ctx, tt.blockID)
if tt.wantErr {
assert.NotEqual(t, err, nil, "no error has been returned")
return
}
if tt.want == nil {
assert.Equal(t, nil, result)
return
}
require.NoError(t, err)
pbBlock, err := result.PbPhase0Block()
require.NoError(t, err)
if !reflect.DeepEqual(pbBlock, tt.want) {
t.Error("Expected blocks to equal")
}
})
}
}

View File

@@ -1,4 +1,4 @@
package statefetcher
package lookup
import (
"bytes"
@@ -71,15 +71,15 @@ func (e *StateRootNotFoundError) Error() string {
return e.message
}
// Fetcher is responsible for retrieving info related with the beacon chain.
type Fetcher interface {
State(ctx context.Context, stateId []byte) (state.BeaconState, error)
StateRoot(ctx context.Context, stateId []byte) ([]byte, error)
// Stater is responsible for retrieving states.
type Stater interface {
State(ctx context.Context, id []byte) (state.BeaconState, error)
StateRoot(ctx context.Context, id []byte) ([]byte, error)
StateBySlot(ctx context.Context, slot primitives.Slot) (state.BeaconState, error)
}
// StateProvider is a real implementation of Fetcher.
type StateProvider struct {
// BeaconDbStater is an implementation of Stater. It retrieves states from the beacon chain database.
type BeaconDbStater struct {
BeaconDB db.ReadOnlyDatabase
ChainInfoFetcher blockchain.ChainInfoFetcher
GenesisTimeFetcher blockchain.TimeFetcher
@@ -94,7 +94,7 @@ type StateProvider struct {
// - "justified"
// - <slot>
// - <hex encoded state root with '0x' prefix>
func (p *StateProvider) State(ctx context.Context, stateId []byte) (state.BeaconState, error) {
func (p *BeaconDbStater) State(ctx context.Context, stateId []byte) (state.BeaconState, error) {
var (
s state.BeaconState
err error
@@ -164,7 +164,7 @@ func (p *StateProvider) State(ctx context.Context, stateId []byte) (state.Beacon
// - "justified"
// - <slot>
// - <hex encoded state root with '0x' prefix>
func (p *StateProvider) StateRoot(ctx context.Context, stateId []byte) (root []byte, err error) {
func (p *BeaconDbStater) StateRoot(ctx context.Context, stateId []byte) (root []byte, err error) {
stateIdString := strings.ToLower(string(stateId))
switch stateIdString {
case "head":
@@ -192,7 +192,7 @@ func (p *StateProvider) StateRoot(ctx context.Context, stateId []byte) (root []b
return root, err
}
func (p *StateProvider) stateByRoot(ctx context.Context, stateRoot []byte) (state.BeaconState, error) {
func (p *BeaconDbStater) stateByRoot(ctx context.Context, stateRoot []byte) (state.BeaconState, error) {
headState, err := p.ChainInfoFetcher.HeadStateReadOnly(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not get head state")
@@ -213,7 +213,7 @@ func (p *StateProvider) stateByRoot(ctx context.Context, stateRoot []byte) (stat
// between the found state's slot and the target slot.
// process_blocks is applied for all canonical blocks, and process_slots is called for any skipped
// slots, or slots following the most recent canonical block up to and including the target slot.
func (p *StateProvider) StateBySlot(ctx context.Context, target primitives.Slot) (state.BeaconState, error) {
func (p *BeaconDbStater) StateBySlot(ctx context.Context, target primitives.Slot) (state.BeaconState, error) {
ctx, span := trace.StartSpan(ctx, "statefetcher.StateBySlot")
defer span.End()
@@ -229,7 +229,7 @@ func (p *StateProvider) StateBySlot(ctx context.Context, target primitives.Slot)
return st, nil
}
func (p *StateProvider) headStateRoot(ctx context.Context) ([]byte, error) {
func (p *BeaconDbStater) headStateRoot(ctx context.Context) ([]byte, error) {
b, err := p.ChainInfoFetcher.HeadBlock(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not get head block")
@@ -241,7 +241,7 @@ func (p *StateProvider) headStateRoot(ctx context.Context) ([]byte, error) {
return stateRoot[:], nil
}
func (p *StateProvider) genesisStateRoot(ctx context.Context) ([]byte, error) {
func (p *BeaconDbStater) genesisStateRoot(ctx context.Context) ([]byte, error) {
b, err := p.BeaconDB.GenesisBlock(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not get genesis block")
@@ -253,7 +253,7 @@ func (p *StateProvider) genesisStateRoot(ctx context.Context) ([]byte, error) {
return stateRoot[:], nil
}
func (p *StateProvider) finalizedStateRoot(ctx context.Context) ([]byte, error) {
func (p *BeaconDbStater) finalizedStateRoot(ctx context.Context) ([]byte, error) {
cp, err := p.BeaconDB.FinalizedCheckpoint(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not get finalized checkpoint")
@@ -269,7 +269,7 @@ func (p *StateProvider) finalizedStateRoot(ctx context.Context) ([]byte, error)
return stateRoot[:], nil
}
func (p *StateProvider) justifiedStateRoot(ctx context.Context) ([]byte, error) {
func (p *BeaconDbStater) justifiedStateRoot(ctx context.Context) ([]byte, error) {
cp, err := p.BeaconDB.JustifiedCheckpoint(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not get justified checkpoint")
@@ -285,7 +285,7 @@ func (p *StateProvider) justifiedStateRoot(ctx context.Context) ([]byte, error)
return stateRoot[:], nil
}
func (p *StateProvider) stateRootByRoot(ctx context.Context, stateRoot []byte) ([]byte, error) {
func (p *BeaconDbStater) stateRootByRoot(ctx context.Context, stateRoot []byte) ([]byte, error) {
var r [32]byte
copy(r[:], stateRoot)
headState, err := p.ChainInfoFetcher.HeadStateReadOnly(ctx)
@@ -302,7 +302,7 @@ func (p *StateProvider) stateRootByRoot(ctx context.Context, stateRoot []byte) (
return nil, &rootNotFoundErr
}
func (p *StateProvider) stateRootBySlot(ctx context.Context, slot primitives.Slot) ([]byte, error) {
func (p *BeaconDbStater) stateRootBySlot(ctx context.Context, slot primitives.Slot) ([]byte, error) {
currentSlot := p.GenesisTimeFetcher.CurrentSlot()
if slot > currentSlot {
return nil, errors.New("slot cannot be in the future")

View File

@@ -1,4 +1,4 @@
package statefetcher
package lookup
import (
"context"
@@ -38,7 +38,7 @@ func TestGetState(t *testing.T) {
require.NoError(t, err)
t.Run("head", func(t *testing.T) {
p := StateProvider{
p := BeaconDbStater{
ChainInfoFetcher: &chainMock.ChainService{State: newBeaconState},
}
@@ -78,7 +78,7 @@ func TestGetState(t *testing.T) {
cs := &mockstategen.MockCurrentSlotter{Slot: bs.Slot() + 1}
ch := stategen.NewCanonicalHistory(db, cc, cs)
currentSlot := primitives.Slot(0)
p := StateProvider{
p := BeaconDbStater{
BeaconDB: db,
ReplayerBuilder: ch,
GenesisTimeFetcher: &chainMock.ChainService{Slot: &currentSlot},
@@ -98,7 +98,7 @@ func TestGetState(t *testing.T) {
replayer.SetMockStateForSlot(newBeaconState, params.BeaconConfig().SlotsPerEpoch*10)
stateGen.StatesByRoot[stateRoot] = newBeaconState
p := StateProvider{
p := BeaconDbStater{
ChainInfoFetcher: &chainMock.ChainService{
FinalizedCheckPoint: &ethpb.Checkpoint{
Root: stateRoot[:],
@@ -122,7 +122,7 @@ func TestGetState(t *testing.T) {
replayer.SetMockStateForSlot(newBeaconState, params.BeaconConfig().SlotsPerEpoch*10)
stateGen.StatesByRoot[stateRoot] = newBeaconState
p := StateProvider{
p := BeaconDbStater{
ChainInfoFetcher: &chainMock.ChainService{
CurrentJustifiedCheckPoint: &ethpb.Checkpoint{
Root: stateRoot[:],
@@ -146,7 +146,7 @@ func TestGetState(t *testing.T) {
stateGen := mockstategen.NewMockService()
stateGen.StatesByRoot[bytesutil.ToBytes32(stateId)] = newBeaconState
p := StateProvider{
p := BeaconDbStater{
ChainInfoFetcher: &chainMock.ChainService{State: newBeaconState},
StateGenService: stateGen,
}
@@ -159,7 +159,7 @@ func TestGetState(t *testing.T) {
})
t.Run("hex_root_not_found", func(t *testing.T) {
p := StateProvider{
p := BeaconDbStater{
ChainInfoFetcher: &chainMock.ChainService{State: newBeaconState},
}
stateId, err := hexutil.Decode("0x" + strings.Repeat("f", 64))
@@ -169,7 +169,7 @@ func TestGetState(t *testing.T) {
})
t.Run("slot", func(t *testing.T) {
p := StateProvider{
p := BeaconDbStater{
GenesisTimeFetcher: &chainMock.ChainService{Slot: &headSlot},
ChainInfoFetcher: &chainMock.ChainService{
CanonicalRoots: map[[32]byte]bool{
@@ -188,7 +188,7 @@ func TestGetState(t *testing.T) {
})
t.Run("invalid_state", func(t *testing.T) {
p := StateProvider{}
p := BeaconDbStater{}
_, err := p.State(ctx, []byte("foo"))
require.ErrorContains(t, "could not parse state ID", err)
})
@@ -212,7 +212,7 @@ func TestGetStateRoot(t *testing.T) {
b.Block.StateRoot = stateRoot[:]
wsb, err := blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
p := StateProvider{
p := BeaconDbStater{
ChainInfoFetcher: &chainMock.ChainService{
State: newBeaconState,
Block: wsb,
@@ -241,7 +241,7 @@ func TestGetStateRoot(t *testing.T) {
require.NoError(t, db.SaveGenesisBlockRoot(ctx, r))
require.NoError(t, db.SaveState(ctx, bs, r))
p := StateProvider{
p := BeaconDbStater{
BeaconDB: db,
}
@@ -275,7 +275,7 @@ func TestGetStateRoot(t *testing.T) {
require.NoError(t, db.SaveState(ctx, st, root))
require.NoError(t, db.SaveFinalizedCheckpoint(ctx, cp))
p := StateProvider{
p := BeaconDbStater{
BeaconDB: db,
}
@@ -306,7 +306,7 @@ func TestGetStateRoot(t *testing.T) {
require.NoError(t, db.SaveState(ctx, st, root))
require.NoError(t, db.SaveJustifiedCheckpoint(ctx, cp))
p := StateProvider{
p := BeaconDbStater{
BeaconDB: db,
}
@@ -319,7 +319,7 @@ func TestGetStateRoot(t *testing.T) {
stateId, err := hexutil.Decode("0x" + strings.Repeat("0", 63) + "1")
require.NoError(t, err)
p := StateProvider{
p := BeaconDbStater{
ChainInfoFetcher: &chainMock.ChainService{State: newBeaconState},
}
@@ -329,7 +329,7 @@ func TestGetStateRoot(t *testing.T) {
})
t.Run("hex_root_not_found", func(t *testing.T) {
p := StateProvider{
p := BeaconDbStater{
ChainInfoFetcher: &chainMock.ChainService{State: newBeaconState},
}
stateId, err := hexutil.Decode("0x" + strings.Repeat("f", 64))
@@ -355,7 +355,7 @@ func TestGetStateRoot(t *testing.T) {
require.NoError(t, db.SaveState(ctx, st, root))
slot := primitives.Slot(40)
p := StateProvider{
p := BeaconDbStater{
GenesisTimeFetcher: &chainMock.ChainService{Slot: &slot},
BeaconDB: db,
}
@@ -366,7 +366,7 @@ func TestGetStateRoot(t *testing.T) {
})
t.Run("slot_too_big", func(t *testing.T) {
p := StateProvider{
p := BeaconDbStater{
GenesisTimeFetcher: &chainMock.ChainService{
Genesis: time.Now(),
},
@@ -376,7 +376,7 @@ func TestGetStateRoot(t *testing.T) {
})
t.Run("invalid_state", func(t *testing.T) {
p := StateProvider{}
p := BeaconDbStater{}
_, err := p.StateRoot(ctx, []byte("foo"))
require.ErrorContains(t, "could not parse state ID", err)
})
@@ -389,7 +389,7 @@ func TestNewStateNotFoundError(t *testing.T) {
func TestStateBySlot_FutureSlot(t *testing.T) {
slot := primitives.Slot(100)
p := StateProvider{GenesisTimeFetcher: &chainMock.ChainService{Slot: &slot}}
p := BeaconDbStater{GenesisTimeFetcher: &chainMock.ChainService{Slot: &slot}}
_, err := p.StateBySlot(context.Background(), 101)
assert.ErrorContains(t, "requested slot is in the future", err)
}
@@ -403,7 +403,7 @@ func TestStateBySlot_AfterHeadSlot(t *testing.T) {
mock := &chainMock.ChainService{State: headSt, Slot: &currentSlot}
mockReplayer := mockstategen.NewMockReplayerBuilder()
mockReplayer.SetMockStateForSlot(slotSt, 101)
p := StateProvider{ChainInfoFetcher: mock, GenesisTimeFetcher: mock, ReplayerBuilder: mockReplayer}
p := BeaconDbStater{ChainInfoFetcher: mock, GenesisTimeFetcher: mock, ReplayerBuilder: mockReplayer}
st, err := p.StateBySlot(context.Background(), 101)
require.NoError(t, err)
assert.Equal(t, primitives.Slot(101), st.Slot())

View File

@@ -346,12 +346,19 @@ func (bs *Server) StreamBlocks(req *ethpb.StreamBlocksRequest, stream ethpb.Beac
// StreamChainHead to clients every single time the head block and state of the chain change.
// DEPRECATED: This endpoint is superseded by the /eth/v1/events Beacon API endpoint
func (bs *Server) StreamChainHead(_ *emptypb.Empty, stream ethpb.BeaconChain_StreamChainHeadServer) error {
stateChannel := make(chan *feed.Event, 1)
stateChannel := make(chan *feed.Event, 4)
stateSub := bs.StateNotifier.StateFeed().Subscribe(stateChannel)
defer stateSub.Unsubscribe()
for {
select {
case stateEvent := <-stateChannel:
// In the event our node is in sync mode
// we do not send the chainhead to the caller
// due to the possibility of deadlocks when retrieving
// all the chain related data.
if bs.SyncChecker.Syncing() {
continue
}
if stateEvent.Type == statefeed.BlockProcessed {
res, err := bs.chainHeadRetrieval(stream.Context())
if err != nil {

View File

@@ -13,6 +13,7 @@ import (
statefeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/state"
dbTest "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing"
state_native "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native"
mockSync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync/initial-sync/testing"
"github.com/prysmaticlabs/prysm/v4/config/features"
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
"github.com/prysmaticlabs/prysm/v4/config/params"
@@ -287,6 +288,7 @@ func TestServer_StreamChainHead_OnHeadUpdated(t *testing.T) {
CurrentJustifiedCheckPoint: s.CurrentJustifiedCheckpoint(),
PreviousJustifiedCheckPoint: s.PreviousJustifiedCheckpoint()},
OptimisticModeFetcher: &chainMock.ChainService{},
SyncChecker: &mockSync.Sync{IsSyncing: false},
}
exitRoutine := make(chan bool)
ctrl := gomock.NewController(t)

View File

@@ -46,6 +46,5 @@ type Server struct {
StateGen stategen.StateManager
SyncChecker sync.Checker
ReplayerBuilder stategen.ReplayerBuilder
HeadUpdater blockchain.HeadUpdater
OptimisticModeFetcher blockchain.OptimisticModeFetcher
}

View File

@@ -503,7 +503,7 @@ func (bs *Server) GetValidatorParticipation(
if err != nil {
return nil, err
}
// Get as close as we can to the end of the current epoch without going past the curent slot.
// Get as close as we can to the end of the current epoch without going past the current slot.
// The above check ensures a future *epoch* isn't requested, but the end slot of the requested epoch could still
// be past the current slot. In that case, use the current slot as the best approximation of the requested epoch.
// Replayer will make sure the slot ultimately used is canonical.

View File

@@ -49,14 +49,12 @@ func (vs *Server) GetBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (
}
// process attestations and update head in forkchoice
vs.ForkFetcher.ForkChoicer().Lock()
vs.HeadUpdater.UpdateHead(ctx, vs.ForkFetcher.CurrentSlot())
headRoot := vs.ForkFetcher.ForkChoicer().CachedHeadRoot()
parentRoot := vs.ForkFetcher.ForkChoicer().GetProposerHead()
vs.ForkchoiceFetcher.UpdateHead(ctx, vs.TimeFetcher.CurrentSlot())
headRoot := vs.ForkchoiceFetcher.CachedHeadRoot()
parentRoot := vs.ForkchoiceFetcher.GetProposerHead()
if parentRoot != headRoot {
blockchain.LateBlockAttemptedReorgCount.Inc()
}
vs.ForkFetcher.ForkChoicer().Unlock()
// An optimistic validator MUST NOT produce a block (i.e., sign across the DOMAIN_BEACON_PROPOSER domain).
if slots.ToEpoch(req.Slot) >= params.BeaconConfig().BellatrixForkEpoch {

View File

@@ -4,6 +4,7 @@ import (
"bytes"
"context"
"fmt"
"math/big"
"time"
"github.com/pkg/errors"
@@ -32,6 +33,8 @@ var builderGetPayloadMissCount = promauto.NewCounter(prometheus.CounterOpts{
Help: "The number of get payload misses for validator requests to builder",
})
var gweiPerEth = big.NewInt(int64(params.BeaconConfig().GweiPerEth))
// blockBuilderTimeout is the maximum amount of time allowed for a block builder to respond to a
// block request. This value is known as `BUILDER_PROPOSAL_DELAY_TOLERANCE` in builder spec.
const blockBuilderTimeout = 1 * time.Second
@@ -60,43 +63,58 @@ func (vs *Server) setExecutionData(ctx context.Context, blk interfaces.SignedBea
return errors.Wrap(err, "failed to get execution payload")
}
// Compare payload values between local and builder. Default to the local value if it is higher.
localValue, err := localPayload.Value()
v, err := localPayload.Value()
if err != nil {
return errors.Wrap(err, "failed to get local payload value")
}
builderValue, err := builderPayload.Value()
v.Div(v, gweiPerEth)
localValue := v.Uint64()
v, err = builderPayload.Value()
if err != nil {
log.WithError(err).Warn("Proposer: failed to get builder payload value") // Default to local if can't get builder value.
v = big.NewInt(0) // Default to local if can't get builder value.
}
v.Div(v, gweiPerEth)
builderValue := v.Uint64()
withdrawalsMatched, err := matchingWithdrawalsRoot(localPayload, builderPayload)
if err != nil {
return errors.Wrap(err, "failed to match withdrawals root")
}
// Use builder payload if the following in true:
// builder_bid_value * 100 > local_block_value * (local-block-value-boost + 100)
boost := params.BeaconConfig().LocalBlockValueBoost
higherValueBuilder := builderValue*100 > localValue*(100+boost)
// If we can't get the builder value, just use local block.
if builderValue.Cmp(localValue) > 0 && withdrawalsMatched { // Builder value is higher and withdrawals match.
if higherValueBuilder && withdrawalsMatched { // Builder value is higher and withdrawals match.
blk.SetBlinded(true)
if err := blk.SetExecution(builderPayload); err != nil {
log.WithError(err).Warn("Proposer: failed to set builder payload")
blk.SetBlinded(false)
} else {
return nil
}
}
log.WithFields(logrus.Fields{
"localValue": localValue,
"builderValue": builderValue,
}).Warn("Proposer: using local execution payload because higher value")
if !higherValueBuilder {
log.WithFields(logrus.Fields{
"localGweiValue": localValue,
"localBoostPercentage": boost,
"builderGweiValue": builderValue,
}).Warn("Proposer: using local execution payload because higher value")
}
return blk.SetExecution(localPayload)
default: // Bellatrix case.
blk.SetBlinded(true)
if err := blk.SetExecution(builderPayload); err != nil {
log.WithError(err).Warn("Proposer: failed to set builder payload")
blk.SetBlinded(false)
} else {
return nil
}
}
}
}
executionData, err := vs.getExecutionPayload(ctx, slot, idx, blk.Block().ParentRoot(), headState)
@@ -137,6 +155,9 @@ func (vs *Server) getPayloadHeaderFromBuilder(ctx context.Context, slot primitiv
if signedBid.IsNil() {
return nil, errors.New("builder returned nil bid")
}
if signedBid.Version() != b.Version() {
return nil, fmt.Errorf("builder bid response version: %d is different from head block version: %d", signedBid.Version(), b.Version())
}
bid, err := signedBid.Message()
if err != nil {
return nil, errors.Wrap(err, "could not get bid")

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