Compare commits

...

32 Commits

Author SHA1 Message Date
prestonvanloon
568cc9a9df temp commit with some commentary. revert this commit later 2022-03-03 11:38:39 -06:00
prestonvanloon
0d08d4f2ca temp commit with some commentary. revert this commit later 2022-03-02 18:32:31 -06:00
prestonvanloon
cb4964b575 temp commit with some commentary. revert this commit later 2022-03-02 18:21:32 -06:00
prestonvanloon
7ed71b27f1 temp commit with some commentary. revert this commit later 2022-03-02 18:18:01 -06:00
prestonvanloon
7710db4ec2 temp commit with some commentary. revert this commit later 2022-03-02 18:05:11 -06:00
prestonvanloon
ff1190a387 temp commit with some commentary. revert this commit later 2022-03-02 17:55:30 -06:00
prestonvanloon
ad849dbac4 temp commit with some commentary. revert this commit later 2022-03-02 17:24:59 -06:00
prestonvanloon
abe667a262 temp commit with some commentary. revert this commit later 2022-03-02 17:21:02 -06:00
prestonvanloon
c51ea298a2 temp commit with some commentary. revert this commit later 2022-03-02 17:16:55 -06:00
prestonvanloon
72b3114f37 temp commit with some commentary. revert this commit later 2022-03-02 17:13:52 -06:00
prestonvanloon
1930550675 temp commit with some commentary. revert this commit later 2022-03-02 15:14:49 -06:00
prestonvanloon
ea68d4b10e temp commit to test e2e 2022-03-02 14:29:06 -06:00
Raul Jordan
958dd9d783 Check Engine API Transition Configuration in Background (#10250)
* transition proto

* gen pb

* builds

* impl transition config

* begin tests

* transition config messed up

* amend proto

* use str

* passing

* gaz

* config

* client test

* pb

* set to 0

* rem log

* gaz

* check transition config

* check config differences

* check transition config in background

* gaz

* pass

* redundant

* fix up error handling and healthz

* simplify status

* gazelle

* build

* err config check

* test

* gaz

* Fix run time

Co-authored-by: terence tsao <terence@prysmaticlabs.com>
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2022-03-01 21:38:51 +00:00
Preston Van Loon
a3f8ccd924 validator: Fix flaky test TestServer_RefreshJWTSecretOnFileChange (#10296) 2022-03-01 20:34:05 +00:00
terence tsao
d64f6cb7a8 Add engine methods to block processing (#10285)
* Add notify newPayload and forkchoiceUpdate

* Tests

* Raul's feedback

* Update optimistic_sync.go

* Simplify

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2022-03-01 16:43:06 +00:00
terence tsao
a9a75e0004 Release lock before return validatedTips (#10289)
* Release lock before return

* add test

Co-authored-by: Potuz <potuz@prysmaticlabs.com>
2022-03-01 15:36:47 +00:00
Nishant Das
339540274b Integration of Vectorized Sha256 In Prysm (#10166)
* add changes

* fix for vectorize

* fix bug

* add new bench

* use new algorithms

* add latest updates

* save progress

* hack even more

* add more changes

* change library

* go mod

* fix deps

* fix dumb bug

* add flag and remove redundant code

* clean up better

* remove those ones

* clean up benches

* clean up benches

* cleanup

* gaz

* revert change

* potuz's review

* potuz's review

* potuz's review

* gaz

* potuz's review

* remove cyclical import

* revert ide changes

* potuz's review

* return
2022-02-28 21:56:12 +08:00
Raul Jordan
12ba8f3645 Renaming Random in ExecutionPayloads to PrevRandao (#10283)
* rename proto

* p header

* regen

* regen ssz

* fix randao

* random name changes

* bazel builds

* bt

* incorrect prev randao

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2022-02-26 03:47:16 +00:00
Raul Jordan
f3a7f399c0 Engine API Client Authentication for the Merge via HTTP (#10236)
* round tripper with claims

* auth

* edit auth

* test out jwt

* passing

* jwt flag

* comment

* passing

* commentary

* fix up jwt parsing

* gaz

* update jwt libs

* tidy

* gaz

* lint

* tidy up

* comment too long

Co-authored-by: james-prysm <90280386+james-prysm@users.noreply.github.com>
2022-02-25 19:08:43 +00:00
james-prysm
6163e091a7 web3signer: fixes for e2e (#10281)
* fixing logs and caught bug in mappers

* Fix schema

* improving logging

* Update validator/keymanager/remote-web3signer/internal/client.go

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

* adding logurus dependency

Co-authored-by: prestonvanloon <preston@prysmaticlabs.com>
2022-02-25 02:42:26 +00:00
terence tsao
2fb4ddcbe7 Engine API: add payload status handling and tests (#10282)
* Add status handling and tests

* Update client.go

* Fmt

* Update mock_engine_test.go

* Update client_test.go
2022-02-24 19:35:01 +00:00
Radosław Kapka
1c2e463a30 --api-timeout flag (#10260)
* `--api-timeout` flag

* simplify code

* review feedback

* better error handling

* better docs

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2022-02-24 18:01:37 +00:00
james-prysm
01e9125761 web3signer: url parsing bug (#10278)
* adding in fixes for url

* fixing gazelle

* fixing wrong keymanager kind

* adding required scheme to urls

* fixing another unit test

* removing unused file

* adding new commit to retrigger deepsource ci
2022-02-24 10:24:11 -06:00
terence tsao
02a088d93c Add validate_merge_block (#10273)
* Add

* Update pow_block.go

* Update BUILD.bazel

* Update beacon-chain/blockchain/pow_block.go

Co-authored-by: Radosław Kapka <rkapka@wp.pl>

* feedbacks

* Feedbacks

* Fmt

* Update BUILD.bazel

* Update BUILD.bazel

* Update pow_block_test.go

Co-authored-by: Radosław Kapka <rkapka@wp.pl>
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2022-02-23 22:41:11 +00:00
terence tsao
8cadb2ac6f Update IsOptimistic to always false (#10276)
* Update  to always false

* Use epoch

* Update chain_info_test.go

* Update chain_info_test.go
2022-02-23 20:16:45 +00:00
Potuz
be722604f7 Fix logarithm of 2 (#10275)
* Fix logarithm of 2

* add regression test

* Update encoding/ssz/merkleize.go

Co-authored-by: Nishant Das <nishdas93@gmail.com>

Co-authored-by: Nishant Das <nishdas93@gmail.com>
2022-02-23 12:44:04 +00:00
Raul Jordan
3bb2acfc7d Update Web UI to v1.0.3 (#10264)
* update web UI version

* fixing format

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
Co-authored-by: James He <james@prysmaticlabs.com>
2022-02-22 18:26:15 +00:00
terence tsao
7719356b69 Add opt sync bool to IsOptimistic (#10270)
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2022-02-22 16:46:42 +00:00
Raul Jordan
75b9bdba7c Small Comment Fix in Exchanging Transition Config (#10271) 2022-02-22 16:16:02 +00:00
Nishant Das
525c818672 Remove SSZ Cache (#10256)
* remove ssz cache

* gaz

* lint

* analyze more

* fix
2022-02-22 17:27:51 +08:00
terence tsao
a55fdf8949 Use type string for total_difficulty (#10265)
* Use string for difficulty

* fix go

* fix test

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
Co-authored-by: Potuz <potuz@prysmaticlabs.com>
2022-02-21 14:03:12 +00:00
Preston Van Loon
7f41b69281 Wrapper: Update block interface and reorganize fork logic (#10267)
* Add ssz.HashRoot interface composition to BeaconBlock interface, move fork specific logic into it's own files

* Remove needless underscore
2022-02-20 20:53:05 +00:00
143 changed files with 4488 additions and 2603 deletions

View File

@@ -349,9 +349,9 @@ filegroup(
visibility = ["//visibility:public"],
)
""",
sha256 = "f196fe4367c2d2d01d36565c0dc6eecfa4f03adba1fc03a61d62953fce606e1f",
sha256 = "4797a7e594a5b1f4c1c8080701613f3ee451b01ec0861499ea7d9b60877a6b23",
urls = [
"https://github.com/prysmaticlabs/prysm-web-ui/releases/download/v1.0.2/prysm-web-ui.tar.gz",
"https://github.com/prysmaticlabs/prysm-web-ui/releases/download/v1.0.3/prysm-web-ui.tar.gz",
],
)

View File

@@ -3,6 +3,7 @@ package apimiddleware
import (
"net/http"
"reflect"
"time"
"github.com/gorilla/mux"
)
@@ -14,6 +15,7 @@ import (
type ApiProxyMiddleware struct {
GatewayAddress string
EndpointCreator EndpointFactory
Timeout time.Duration
router *mux.Router
}
@@ -120,7 +122,7 @@ func (m *ApiProxyMiddleware) WithMiddleware(path string) http.HandlerFunc {
WriteError(w, errJson, nil)
return
}
grpcResp, errJson := ProxyRequest(req)
grpcResp, errJson := m.ProxyRequest(req)
if errJson != nil {
WriteError(w, errJson, nil)
return

View File

@@ -5,10 +5,10 @@ import (
"encoding/json"
"io"
"io/ioutil"
"net"
"net/http"
"strconv"
"strings"
"time"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/api/grpc"
@@ -75,11 +75,14 @@ func (m *ApiProxyMiddleware) PrepareRequestForProxying(endpoint Endpoint, req *h
}
// ProxyRequest proxies the request to grpc-gateway.
func ProxyRequest(req *http.Request) (*http.Response, ErrorJson) {
func (m *ApiProxyMiddleware) ProxyRequest(req *http.Request) (*http.Response, ErrorJson) {
// We do not use http.DefaultClient because it does not have any timeout.
netClient := &http.Client{Timeout: time.Minute * 2}
netClient := &http.Client{Timeout: m.Timeout}
grpcResp, err := netClient.Do(req)
if err != nil {
if err, ok := err.(net.Error); ok && err.Timeout() {
return nil, TimeoutError()
}
return nil, InternalServerErrorWithMessage(err, "could not proxy request")
}
if grpcResp == nil {
@@ -111,9 +114,14 @@ func HandleGrpcResponseError(errJson ErrorJson, resp *http.Response, respBody []
w.Header().Set(h, v)
}
}
// Set code to HTTP code because unmarshalled body contained gRPC code.
errJson.SetCode(resp.StatusCode)
WriteError(w, errJson, resp.Header)
// Handle gRPC timeout.
if resp.StatusCode == http.StatusGatewayTimeout {
WriteError(w, TimeoutError(), resp.Header)
} else {
// Set code to HTTP code because unmarshalled body contained gRPC code.
errJson.SetCode(resp.StatusCode)
WriteError(w, errJson, resp.Header)
}
}
return responseHasError, nil
}

View File

@@ -41,6 +41,13 @@ func InternalServerError(err error) *DefaultErrorJson {
}
}
func TimeoutError() *DefaultErrorJson {
return &DefaultErrorJson{
Message: "Request timeout",
Code: http.StatusRequestTimeout,
}
}
// StatusCode returns the error's underlying error code.
func (e *DefaultErrorJson) StatusCode() int {
return e.Code

View File

@@ -52,6 +52,7 @@ type config struct {
muxHandler MuxHandler
pbHandlers []*PbMux
router *mux.Router
timeout time.Duration
}
// Gateway is the gRPC gateway to serve HTTP JSON traffic as a proxy and forward it to the gRPC server.
@@ -248,6 +249,7 @@ func (g *Gateway) registerApiMiddleware() {
g.proxy = &apimiddleware.ApiProxyMiddleware{
GatewayAddress: g.cfg.gatewayAddr,
EndpointCreator: g.cfg.apiMiddlewareEndpointFactory,
Timeout: g.cfg.timeout,
}
log.Info("Starting API middleware")
g.proxy.Run(g.cfg.router)

View File

@@ -1,7 +1,10 @@
package gateway
import (
"time"
"github.com/gorilla/mux"
gwruntime "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/prysmaticlabs/prysm/api/gateway/apimiddleware"
)
@@ -79,3 +82,12 @@ func WithApiMiddleware(endpointFactory apimiddleware.EndpointFactory) Option {
return nil
}
}
// WithTimeout allows changing the timeout value for API calls.
func WithTimeout(seconds uint64) Option {
return func(g *Gateway) error {
g.cfg.timeout = time.Second * time.Duration(seconds)
gwruntime.DefaultContextTimeout = time.Second * time.Duration(seconds)
return nil
}
}

View File

@@ -56,6 +56,7 @@ go_library(
"//beacon-chain/operations/voluntaryexits:go_default_library",
"//beacon-chain/p2p:go_default_library",
"//beacon-chain/powchain:go_default_library",
"//beacon-chain/powchain/engine-api-client/v1:go_default_library",
"//beacon-chain/state:go_default_library",
"//beacon-chain/state/stategen:go_default_library",
"//cmd/beacon-chain/flags:go_default_library",
@@ -65,6 +66,7 @@ go_library(
"//crypto/bls:go_default_library",
"//encoding/bytesutil:go_default_library",
"//monitoring/tracing:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/eth/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/attestation:go_default_library",
@@ -73,6 +75,8 @@ go_library(
"//time:go_default_library",
"//time/slots:go_default_library",
"@com_github_emicklei_dot//:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
"@com_github_holiman_uint256//:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_prometheus_client_golang//prometheus:go_default_library",
@@ -104,6 +108,7 @@ go_test(
"init_test.go",
"log_test.go",
"metrics_test.go",
"mock_engine_test.go",
"mock_test.go",
"optimistic_sync_test.go",
"pow_block_test.go",

View File

@@ -13,6 +13,7 @@ import (
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
"github.com/prysmaticlabs/prysm/time/slots"
"go.opencensus.io/trace"
)
@@ -334,6 +335,10 @@ func (s *Service) HeadValidatorIndexToPublicKey(_ context.Context, index types.V
func (s *Service) IsOptimistic(ctx context.Context) (bool, error) {
s.headLock.RLock()
defer s.headLock.RUnlock()
if slots.ToEpoch(s.CurrentSlot()) < params.BeaconConfig().BellatrixForkEpoch {
return false, nil
}
return s.cfg.ForkChoiceStore.Optimistic(ctx, s.head.root, s.head.slot)
}

View File

@@ -357,6 +357,11 @@ func TestService_HeadValidatorIndexToPublicKeyNil(t *testing.T) {
}
func TestService_IsOptimistic(t *testing.T) {
params.SetupTestConfigCleanup(t)
cfg := params.BeaconConfig()
cfg.BellatrixForkEpoch = 0
params.OverrideBeaconConfig(cfg)
ctx := context.Background()
c := &Service{cfg: &config{ForkChoiceStore: protoarray.New(0, 0, [32]byte{})}, head: &head{slot: 101, root: [32]byte{'b'}}}
require.NoError(t, c.cfg.ForkChoiceStore.ProcessBlock(ctx, 100, [32]byte{'a'}, [32]byte{}, [32]byte{}, 0, 0))
@@ -367,6 +372,14 @@ func TestService_IsOptimistic(t *testing.T) {
require.Equal(t, true, opt)
}
func TestService_IsOptimisticBeforeBellatrix(t *testing.T) {
ctx := context.Background()
c := &Service{genesisTime: time.Now()}
opt, err := c.IsOptimistic(ctx)
require.NoError(t, err)
require.Equal(t, false, opt)
}
func TestService_IsOptimisticForRoot(t *testing.T) {
ctx := context.Background()
c := &Service{cfg: &config{ForkChoiceStore: protoarray.New(0, 0, [32]byte{})}, head: &head{slot: 101, root: [32]byte{'b'}}}

View File

@@ -0,0 +1,49 @@
package blockchain
import (
"context"
"github.com/ethereum/go-ethereum/common"
"github.com/pkg/errors"
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
)
type mockEngineService struct {
newPayloadError error
forkchoiceError error
blks map[[32]byte]*enginev1.ExecutionBlock
}
func (m *mockEngineService) NewPayload(context.Context, *enginev1.ExecutionPayload) ([]byte, error) {
return nil, m.newPayloadError
}
func (m *mockEngineService) ForkchoiceUpdated(context.Context, *enginev1.ForkchoiceState, *enginev1.PayloadAttributes) (*enginev1.PayloadIDBytes, []byte, error) {
return nil, nil, m.forkchoiceError
}
func (*mockEngineService) GetPayloadV1(
_ context.Context, _ enginev1.PayloadIDBytes,
) *enginev1.ExecutionPayload {
return nil
}
func (*mockEngineService) GetPayload(context.Context, [8]byte) (*enginev1.ExecutionPayload, error) {
return nil, nil
}
func (*mockEngineService) ExchangeTransitionConfiguration(context.Context, *enginev1.TransitionConfiguration) error {
return nil
}
func (*mockEngineService) LatestExecutionBlock(context.Context) (*enginev1.ExecutionBlock, error) {
return nil, nil
}
func (m *mockEngineService) ExecutionBlockByHash(_ context.Context, hash common.Hash) (*enginev1.ExecutionBlock, error) {
blk, ok := m.blks[common.BytesToHash(hash.Bytes())]
if !ok {
return nil, errors.New("block not found")
}
return blk, nil
}

View File

@@ -2,15 +2,140 @@ package blockchain
import (
"context"
"fmt"
"github.com/pkg/errors"
types "github.com/prysmaticlabs/eth2-types"
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
v1 "github.com/prysmaticlabs/prysm/beacon-chain/powchain/engine-api-client/v1"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
"github.com/prysmaticlabs/prysm/runtime/version"
"github.com/sirupsen/logrus"
)
// notifyForkchoiceUpdate signals execution engine the fork choice updates. Execution engine should:
// 1. Re-organizes the execution payload chain and corresponding state to make head_block_hash the head.
// 2. Applies finality to the execution state: it irreversibly persists the chain of all execution payloads and corresponding state, up to and including finalized_block_hash.
func (s *Service) notifyForkchoiceUpdate(ctx context.Context, headBlk block.BeaconBlock, finalizedRoot [32]byte) (*enginev1.PayloadIDBytes, error) {
if headBlk == nil || headBlk.IsNil() || headBlk.Body().IsNil() {
return nil, errors.New("nil head block")
}
// Must not call fork choice updated until the transition conditions are met on the Pow network.
if isPreBellatrix(headBlk.Version()) {
return nil, nil
}
isExecutionBlk, err := blocks.ExecutionBlock(headBlk.Body())
if err != nil {
return nil, errors.Wrap(err, "could not determine if block is execution block")
}
if !isExecutionBlk {
return nil, nil
}
headPayload, err := headBlk.Body().ExecutionPayload()
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload")
}
finalizedBlock, err := s.cfg.BeaconDB.Block(ctx, s.ensureRootNotZeros(finalizedRoot))
if err != nil {
return nil, errors.Wrap(err, "could not get finalized block")
}
var finalizedHash []byte
if isPreBellatrix(finalizedBlock.Block().Version()) {
finalizedHash = params.BeaconConfig().ZeroHash[:]
} else {
payload, err := finalizedBlock.Block().Body().ExecutionPayload()
if err != nil {
return nil, errors.Wrap(err, "could not get finalized block execution payload")
}
finalizedHash = payload.BlockHash
}
fcs := &enginev1.ForkchoiceState{
HeadBlockHash: headPayload.BlockHash,
SafeBlockHash: headPayload.BlockHash,
FinalizedBlockHash: finalizedHash,
}
// payload attribute is only required when requesting payload, here we are just updating fork choice, so it is nil.
payloadID, _, err := s.cfg.ExecutionEngineCaller.ForkchoiceUpdated(ctx, fcs, nil /*payload attribute*/)
if err != nil {
switch err {
case v1.ErrAcceptedSyncingPayloadStatus:
log.WithFields(logrus.Fields{
"headSlot": headBlk.Slot(),
"headHash": fmt.Sprintf("%#x", bytesutil.Trunc(headPayload.BlockHash)),
"finalizedHash": fmt.Sprintf("%#x", bytesutil.Trunc(finalizedHash)),
}).Info("Called fork choice updated with optimistic block")
return payloadID, nil
default:
return nil, errors.Wrap(err, "could not notify forkchoice update from execution engine")
}
}
return payloadID, nil
}
// notifyForkchoiceUpdate signals execution engine on a new payload
func (s *Service) notifyNewPayload(ctx context.Context, preState, postState state.BeaconState, blk block.SignedBeaconBlock) error {
if preState == nil || postState == nil {
return errors.New("pre and post states must not be nil")
}
// Execution payload is only supported in Bellatrix and beyond.
if isPreBellatrix(postState.Version()) {
return nil
}
if err := helpers.BeaconBlockIsNil(blk); err != nil {
return err
}
body := blk.Block().Body()
enabled, err := blocks.ExecutionEnabled(postState, blk.Block().Body())
if err != nil {
return errors.Wrap(err, "could not determine if execution is enabled")
}
if !enabled {
return nil
}
payload, err := body.ExecutionPayload()
if err != nil {
return errors.Wrap(err, "could not get execution payload")
}
_, err = s.cfg.ExecutionEngineCaller.NewPayload(ctx, payload)
if err != nil {
switch err {
case v1.ErrAcceptedSyncingPayloadStatus:
log.WithFields(logrus.Fields{
"slot": postState.Slot(),
"blockHash": fmt.Sprintf("%#x", bytesutil.Trunc(payload.BlockHash)),
}).Info("Called new payload with optimistic block")
return nil
default:
return errors.Wrap(err, "could not validate execution payload from execution engine")
}
}
// During the transition event, the transition block should be verified for sanity.
if isPreBellatrix(preState.Version()) {
return nil
}
atTransition, err := blocks.MergeTransitionBlock(preState, body)
if err != nil {
return errors.Wrap(err, "could not check if merge block is terminal")
}
if !atTransition {
return nil
}
return s.validateMergeBlock(ctx, blk)
}
// isPreBellatrix returns true if input version is before bellatrix fork.
func isPreBellatrix(v int) bool {
return v == version.Phase0 || v == version.Altair
}
// optimisticCandidateBlock returns true if this block can be optimistically synced.
//
// Spec pseudocode definition:

View File

@@ -7,10 +7,13 @@ import (
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
engine "github.com/prysmaticlabs/prysm/beacon-chain/powchain/engine-api-client/v1"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
v1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper"
@@ -19,6 +22,305 @@ import (
"github.com/prysmaticlabs/prysm/time/slots"
)
func Test_NotifyForkchoiceUpdate(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
altairBlk, err := wrapper.WrappedSignedBeaconBlock(util.NewBeaconBlockAltair())
require.NoError(t, err)
altairBlkRoot, err := altairBlk.Block().HashTreeRoot()
require.NoError(t, err)
bellatrixBlk, err := wrapper.WrappedSignedBeaconBlock(util.NewBeaconBlockBellatrix())
require.NoError(t, err)
bellatrixBlkRoot, err := bellatrixBlk.Block().HashTreeRoot()
require.NoError(t, err)
require.NoError(t, beaconDB.SaveBlock(ctx, altairBlk))
require.NoError(t, beaconDB.SaveBlock(ctx, bellatrixBlk))
fcs := protoarray.New(0, 0, [32]byte{'a'})
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
WithForkChoiceStore(fcs),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
tests := []struct {
name string
blk block.BeaconBlock
finalizedRoot [32]byte
newForkchoiceErr error
errString string
}{
{
name: "nil block",
errString: "nil head block",
},
{
name: "phase0 block",
blk: func() block.BeaconBlock {
b, err := wrapper.WrappedBeaconBlock(&ethpb.BeaconBlock{Body: &ethpb.BeaconBlockBody{}})
require.NoError(t, err)
return b
}(),
},
{
name: "altair block",
blk: func() block.BeaconBlock {
b, err := wrapper.WrappedBeaconBlock(&ethpb.BeaconBlockAltair{Body: &ethpb.BeaconBlockBodyAltair{}})
require.NoError(t, err)
return b
}(),
},
{
name: "not execution block",
blk: func() block.BeaconBlock {
b, err := wrapper.WrappedBeaconBlock(&ethpb.BeaconBlockBellatrix{
Body: &ethpb.BeaconBlockBodyBellatrix{
ExecutionPayload: &v1.ExecutionPayload{
ParentHash: make([]byte, fieldparams.RootLength),
FeeRecipient: make([]byte, fieldparams.FeeRecipientLength),
StateRoot: make([]byte, fieldparams.RootLength),
ReceiptsRoot: make([]byte, fieldparams.RootLength),
LogsBloom: make([]byte, fieldparams.LogsBloomLength),
PrevRandao: make([]byte, fieldparams.RootLength),
BaseFeePerGas: make([]byte, fieldparams.RootLength),
BlockHash: make([]byte, fieldparams.RootLength),
},
},
})
require.NoError(t, err)
return b
}(),
},
{
name: "happy case: finalized root is altair block",
blk: func() block.BeaconBlock {
b, err := wrapper.WrappedBeaconBlock(&ethpb.BeaconBlockBellatrix{
Body: &ethpb.BeaconBlockBodyBellatrix{
ExecutionPayload: &v1.ExecutionPayload{},
},
})
require.NoError(t, err)
return b
}(),
finalizedRoot: altairBlkRoot,
},
{
name: "happy case: finalized root is bellatrix block",
blk: func() block.BeaconBlock {
b, err := wrapper.WrappedBeaconBlock(&ethpb.BeaconBlockBellatrix{
Body: &ethpb.BeaconBlockBodyBellatrix{
ExecutionPayload: &v1.ExecutionPayload{},
},
})
require.NoError(t, err)
return b
}(),
finalizedRoot: bellatrixBlkRoot,
},
{
name: "forkchoice updated with optimistic block",
blk: func() block.BeaconBlock {
b, err := wrapper.WrappedBeaconBlock(&ethpb.BeaconBlockBellatrix{
Body: &ethpb.BeaconBlockBodyBellatrix{
ExecutionPayload: &v1.ExecutionPayload{},
},
})
require.NoError(t, err)
return b
}(),
newForkchoiceErr: engine.ErrAcceptedSyncingPayloadStatus,
finalizedRoot: bellatrixBlkRoot,
},
{
name: "forkchoice updated with invalid block",
blk: func() block.BeaconBlock {
b, err := wrapper.WrappedBeaconBlock(&ethpb.BeaconBlockBellatrix{
Body: &ethpb.BeaconBlockBodyBellatrix{
ExecutionPayload: &v1.ExecutionPayload{},
},
})
require.NoError(t, err)
return b
}(),
newForkchoiceErr: engine.ErrInvalidPayloadStatus,
finalizedRoot: bellatrixBlkRoot,
errString: "could not notify forkchoice update from execution engine: payload status is INVALID",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
engine := &mockEngineService{forkchoiceError: tt.newForkchoiceErr}
service.cfg.ExecutionEngineCaller = engine
_, err := service.notifyForkchoiceUpdate(ctx, tt.blk, tt.finalizedRoot)
if tt.errString != "" {
require.ErrorContains(t, tt.errString, err)
} else {
require.NoError(t, err)
}
})
}
}
func Test_NotifyNewPayload(t *testing.T) {
cfg := params.BeaconConfig()
cfg.TerminalTotalDifficulty = "2"
params.OverrideBeaconConfig(cfg)
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0, [32]byte{'a'})
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
WithForkChoiceStore(fcs),
}
phase0State, _ := util.DeterministicGenesisState(t, 1)
altairState, _ := util.DeterministicGenesisStateAltair(t, 1)
bellatrixState, _ := util.DeterministicGenesisStateBellatrix(t, 2)
blk := &ethpb.SignedBeaconBlockBellatrix{
Block: &ethpb.BeaconBlockBellatrix{
Body: &ethpb.BeaconBlockBodyBellatrix{
ExecutionPayload: &v1.ExecutionPayload{},
},
},
}
bellatrixBlk, err := wrapper.WrappedSignedBeaconBlock(blk)
require.NoError(t, err)
service, err := NewService(ctx, opts...)
require.NoError(t, err)
tests := []struct {
name string
preState state.BeaconState
postState state.BeaconState
blk block.SignedBeaconBlock
newPayloadErr error
errString string
}{
{
name: "phase 0 post state",
postState: phase0State,
preState: phase0State,
},
{
name: "altair post state",
postState: altairState,
preState: altairState,
},
{
name: "nil states",
errString: "pre and post states must not be nil",
},
{
name: "nil beacon block",
postState: bellatrixState,
preState: bellatrixState,
errString: "signed beacon block can't be nil",
},
{
name: "new payload with optimistic block",
postState: bellatrixState,
preState: bellatrixState,
blk: bellatrixBlk,
newPayloadErr: engine.ErrAcceptedSyncingPayloadStatus,
},
{
name: "new payload with invalid block",
postState: bellatrixState,
preState: bellatrixState,
blk: bellatrixBlk,
newPayloadErr: engine.ErrInvalidPayloadStatus,
errString: "could not validate execution payload from execution engine: payload status is INVALID",
},
{
name: "altair pre state",
postState: bellatrixState,
preState: altairState,
blk: bellatrixBlk,
},
{
name: "could not get merge block",
postState: bellatrixState,
preState: bellatrixState,
blk: bellatrixBlk,
errString: "could not get merge block parent hash and total difficulty",
},
{
name: "not at merge transition",
postState: bellatrixState,
preState: bellatrixState,
blk: func() block.SignedBeaconBlock {
blk := &ethpb.SignedBeaconBlockBellatrix{
Block: &ethpb.BeaconBlockBellatrix{
Body: &ethpb.BeaconBlockBodyBellatrix{
ExecutionPayload: &v1.ExecutionPayload{
ParentHash: make([]byte, fieldparams.RootLength),
FeeRecipient: make([]byte, fieldparams.FeeRecipientLength),
StateRoot: make([]byte, fieldparams.RootLength),
ReceiptsRoot: make([]byte, fieldparams.RootLength),
LogsBloom: make([]byte, fieldparams.LogsBloomLength),
PrevRandao: make([]byte, fieldparams.RootLength),
BaseFeePerGas: make([]byte, fieldparams.RootLength),
BlockHash: make([]byte, fieldparams.RootLength),
},
},
},
}
b, err := wrapper.WrappedSignedBeaconBlock(blk)
require.NoError(t, err)
return b
}(),
},
{
name: "could not get merge block",
postState: bellatrixState,
preState: bellatrixState,
blk: bellatrixBlk,
errString: "could not get merge block parent hash and total difficulty",
},
{
name: "happy case",
postState: bellatrixState,
preState: bellatrixState,
blk: func() block.SignedBeaconBlock {
blk := &ethpb.SignedBeaconBlockBellatrix{
Block: &ethpb.BeaconBlockBellatrix{
Body: &ethpb.BeaconBlockBodyBellatrix{
ExecutionPayload: &v1.ExecutionPayload{
ParentHash: bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength),
},
},
},
}
b, err := wrapper.WrappedSignedBeaconBlock(blk)
require.NoError(t, err)
return b
}(),
},
}
for _, tt := range tests {
engine := &mockEngineService{newPayloadError: tt.newPayloadErr, blks: map[[32]byte]*v1.ExecutionBlock{}}
engine.blks[[32]byte{'a'}] = &v1.ExecutionBlock{
ParentHash: bytesutil.PadTo([]byte{'b'}, fieldparams.RootLength),
TotalDifficulty: "0x2",
}
engine.blks[[32]byte{'b'}] = &v1.ExecutionBlock{
ParentHash: bytesutil.PadTo([]byte{'3'}, fieldparams.RootLength),
TotalDifficulty: "0x1",
}
service.cfg.ExecutionEngineCaller = engine
err := service.notifyNewPayload(ctx, tt.preState, tt.postState, tt.blk)
if tt.errString != "" {
require.ErrorContains(t, tt.errString, err)
} else {
require.NoError(t, err)
}
}
}
func Test_IsOptimisticCandidateBlock(t *testing.T) {
params.SetupTestConfigCleanup(t)
params.OverrideBeaconConfig(params.MainnetConfig())
@@ -115,7 +417,7 @@ func Test_IsOptimisticCandidateBlock(t *testing.T) {
blk.Block.Body.ExecutionPayload.StateRoot = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
blk.Block.Body.ExecutionPayload.ReceiptsRoot = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
blk.Block.Body.ExecutionPayload.LogsBloom = bytesutil.PadTo([]byte{'a'}, fieldparams.LogsBloomLength)
blk.Block.Body.ExecutionPayload.Random = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
blk.Block.Body.ExecutionPayload.PrevRandao = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
blk.Block.Body.ExecutionPayload.BaseFeePerGas = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
blk.Block.Body.ExecutionPayload.BlockHash = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
wr, err := wrapper.WrappedBellatrixSignedBeaconBlock(blk)

View File

@@ -1,20 +1,132 @@
package blockchain
import (
"bytes"
"context"
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/holiman/uint256"
"github.com/pkg/errors"
types "github.com/prysmaticlabs/eth2-types"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
"github.com/prysmaticlabs/prysm/time/slots"
"github.com/sirupsen/logrus"
)
// validates terminal pow block by comparing own total difficulty with parent's total difficulty.
// validateMergeBlock validates terminal block hash in the event of manual overrides before checking for total difficulty.
//
// def validate_merge_block(block: BeaconBlock) -> None:
// if TERMINAL_BLOCK_HASH != Hash32():
// # If `TERMINAL_BLOCK_HASH` is used as an override, the activation epoch must be reached.
// assert compute_epoch_at_slot(block.slot) >= TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH
// assert block.body.execution_payload.parent_hash == TERMINAL_BLOCK_HASH
// return
//
// pow_block = get_pow_block(block.body.execution_payload.parent_hash)
// # Check if `pow_block` is available
// assert pow_block is not None
// pow_parent = get_pow_block(pow_block.parent_hash)
// # Check if `pow_parent` is available
// assert pow_parent is not None
// # Check if `pow_block` is a valid terminal PoW block
// assert is_valid_terminal_pow_block(pow_block, pow_parent)
func (s *Service) validateMergeBlock(ctx context.Context, b block.SignedBeaconBlock) error {
if err := helpers.BeaconBlockIsNil(b); err != nil {
return err
}
payload, err := b.Block().Body().ExecutionPayload()
if err != nil {
return err
}
if payload == nil {
return errors.New("nil execution payload")
}
if err := validateTerminalBlockHash(b.Block().Slot(), payload); err != nil {
return errors.Wrap(err, "could not validate terminal block hash")
}
mergeBlockParentHash, mergeBlockTD, err := s.getBlkParentHashAndTD(ctx, payload.ParentHash)
if err != nil {
return errors.Wrap(err, "could not get merge block parent hash and total difficulty")
}
_, mergeBlockParentTD, err := s.getBlkParentHashAndTD(ctx, mergeBlockParentHash)
if err != nil {
return errors.Wrap(err, "could not get merge parent block total difficulty")
}
valid, err := validateTerminalBlockDifficulties(mergeBlockTD, mergeBlockParentTD)
if err != nil {
return err
}
if !valid {
return fmt.Errorf("invalid TTD, configTTD: %s, currentTTD: %s, parentTTD: %s",
params.BeaconConfig().TerminalTotalDifficulty, mergeBlockTD, mergeBlockParentTD)
}
log.WithFields(logrus.Fields{
"slot": b.Block().Slot(),
"mergeBlockHash": common.BytesToHash(payload.ParentHash).String(),
"mergeBlockParentHash": common.BytesToHash(mergeBlockParentHash).String(),
"terminalTotalDifficulty": params.BeaconConfig().TerminalTotalDifficulty,
"mergeBlockTotalDifficulty": mergeBlockTD,
"mergeBlockParentTotalDifficulty": mergeBlockParentTD,
}).Info("Validated terminal block")
return nil
}
// getBlkParentHashAndTD retrieves the parent hash and total difficulty of the given block.
func (s *Service) getBlkParentHashAndTD(ctx context.Context, blkHash []byte) ([]byte, *uint256.Int, error) {
blk, err := s.cfg.ExecutionEngineCaller.ExecutionBlockByHash(ctx, common.BytesToHash(blkHash))
if err != nil {
return nil, nil, errors.Wrap(err, "could not get pow block")
}
if blk == nil {
return nil, nil, errors.New("pow block is nil")
}
blkTDBig, err := hexutil.DecodeBig(blk.TotalDifficulty)
if err != nil {
return nil, nil, errors.Wrap(err, "could not decode merge block total difficulty")
}
blkTDUint256, overflows := uint256.FromBig(blkTDBig)
if overflows {
return nil, nil, errors.New("total difficulty overflows")
}
return blk.ParentHash, blkTDUint256, nil
}
// validateTerminalBlockHash validates if the merge block is a valid terminal PoW block.
// spec code:
// if TERMINAL_BLOCK_HASH != Hash32():
// # If `TERMINAL_BLOCK_HASH` is used as an override, the activation epoch must be reached.
// assert compute_epoch_at_slot(block.slot) >= TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH
// assert block.body.execution_payload.parent_hash == TERMINAL_BLOCK_HASH
// return
func validateTerminalBlockHash(blkSlot types.Slot, payload *enginev1.ExecutionPayload) error {
if bytesutil.ToBytes32(params.BeaconConfig().TerminalBlockHash.Bytes()) == [32]byte{} {
return nil
}
if params.BeaconConfig().TerminalBlockHashActivationEpoch > slots.ToEpoch(blkSlot) {
return errors.New("terminal block hash activation epoch not reached")
}
if !bytes.Equal(payload.ParentHash, params.BeaconConfig().TerminalBlockHash.Bytes()) {
return errors.New("parent hash does not match terminal block hash")
}
return nil
}
// validateTerminalBlockDifficulties validates terminal pow block by comparing own total difficulty with parent's total difficulty.
//
// def is_valid_terminal_pow_block(block: PowBlock, parent: PowBlock) -> bool:
// is_total_difficulty_reached = block.total_difficulty >= TERMINAL_TOTAL_DIFFICULTY
// is_parent_total_difficulty_valid = parent.total_difficulty < TERMINAL_TOTAL_DIFFICULTY
// return is_total_difficulty_reached and is_parent_total_difficulty_valid
func validTerminalPowBlock(currentDifficulty *uint256.Int, parentDifficulty *uint256.Int) (bool, error) {
func validateTerminalBlockDifficulties(currentDifficulty *uint256.Int, parentDifficulty *uint256.Int) (bool, error) {
b, ok := new(big.Int).SetString(params.BeaconConfig().TerminalTotalDifficulty, 10)
if !ok {
return false, errors.New("failed to parse terminal total difficulty")

View File

@@ -1,12 +1,21 @@
package blockchain
import (
"context"
"fmt"
"math/big"
"testing"
"github.com/holiman/uint256"
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper"
"github.com/prysmaticlabs/prysm/testing/require"
)
@@ -66,10 +75,10 @@ func Test_validTerminalPowBlock(t *testing.T) {
cfg := params.BeaconConfig()
cfg.TerminalTotalDifficulty = fmt.Sprint(tt.ttd)
params.OverrideBeaconConfig(cfg)
got, err := validTerminalPowBlock(tt.currentDifficulty, tt.parentDifficulty)
got, err := validateTerminalBlockDifficulties(tt.currentDifficulty, tt.parentDifficulty)
require.NoError(t, err)
if got != tt.want {
t.Errorf("validTerminalPowBlock() = %v, want %v", got, tt.want)
t.Errorf("validateTerminalBlockDifficulties() = %v, want %v", got, tt.want)
}
})
}
@@ -87,7 +96,115 @@ func Test_validTerminalPowBlockSpecConfig(t *testing.T) {
parent, of := uint256.FromBig(i)
require.Equal(t, of, false)
got, err := validTerminalPowBlock(current, parent)
got, err := validateTerminalBlockDifficulties(current, parent)
require.NoError(t, err)
require.Equal(t, true, got)
}
func Test_validateMergeBlock(t *testing.T) {
cfg := params.BeaconConfig()
cfg.TerminalTotalDifficulty = "2"
params.OverrideBeaconConfig(cfg)
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0, [32]byte{'a'})
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
WithForkChoiceStore(fcs),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
engine := &mockEngineService{blks: map[[32]byte]*enginev1.ExecutionBlock{}}
service.cfg.ExecutionEngineCaller = engine
engine.blks[[32]byte{'a'}] = &enginev1.ExecutionBlock{
ParentHash: bytesutil.PadTo([]byte{'b'}, fieldparams.RootLength),
TotalDifficulty: "0x2",
}
engine.blks[[32]byte{'b'}] = &enginev1.ExecutionBlock{
ParentHash: bytesutil.PadTo([]byte{'3'}, fieldparams.RootLength),
TotalDifficulty: "0x1",
}
blk := &ethpb.SignedBeaconBlockBellatrix{
Block: &ethpb.BeaconBlockBellatrix{
Slot: 1,
Body: &ethpb.BeaconBlockBodyBellatrix{
ExecutionPayload: &enginev1.ExecutionPayload{
ParentHash: bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength),
},
},
},
}
b, err := wrapper.WrappedSignedBeaconBlock(blk)
require.NoError(t, err)
require.NoError(t, service.validateMergeBlock(ctx, b))
cfg.TerminalTotalDifficulty = "1"
params.OverrideBeaconConfig(cfg)
require.ErrorContains(t, "invalid TTD, configTTD: 1, currentTTD: 2, parentTTD: 1", service.validateMergeBlock(ctx, b))
}
func Test_getBlkParentHashAndTD(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := protoarray.New(0, 0, [32]byte{'a'})
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
WithForkChoiceStore(fcs),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
engine := &mockEngineService{blks: map[[32]byte]*enginev1.ExecutionBlock{}}
service.cfg.ExecutionEngineCaller = engine
h := [32]byte{'a'}
p := [32]byte{'b'}
td := "0x1"
engine.blks[h] = &enginev1.ExecutionBlock{
ParentHash: p[:],
TotalDifficulty: td,
}
parentHash, totalDifficulty, err := service.getBlkParentHashAndTD(ctx, h[:])
require.NoError(t, err)
require.Equal(t, p, bytesutil.ToBytes32(parentHash))
require.Equal(t, td, totalDifficulty.String())
_, _, err = service.getBlkParentHashAndTD(ctx, []byte{'c'})
require.ErrorContains(t, "could not get pow block: block not found", err)
engine.blks[h] = nil
_, _, err = service.getBlkParentHashAndTD(ctx, h[:])
require.ErrorContains(t, "pow block is nil", err)
engine.blks[h] = &enginev1.ExecutionBlock{
ParentHash: p[:],
TotalDifficulty: "1",
}
_, _, err = service.getBlkParentHashAndTD(ctx, h[:])
require.ErrorContains(t, "could not decode merge block total difficulty: hex string without 0x prefix", err)
engine.blks[h] = &enginev1.ExecutionBlock{
ParentHash: p[:],
TotalDifficulty: "0XFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
}
_, _, err = service.getBlkParentHashAndTD(ctx, h[:])
require.ErrorContains(t, "could not decode merge block total difficulty: hex number > 256 bits", err)
}
func Test_validateTerminalBlockHash(t *testing.T) {
require.NoError(t, validateTerminalBlockHash(1, &enginev1.ExecutionPayload{}))
cfg := params.BeaconConfig()
cfg.TerminalBlockHash = [32]byte{0x01}
params.OverrideBeaconConfig(cfg)
require.ErrorContains(t, "terminal block hash activation epoch not reached", validateTerminalBlockHash(1, &enginev1.ExecutionPayload{}))
cfg.TerminalBlockHashActivationEpoch = 0
params.OverrideBeaconConfig(cfg)
require.ErrorContains(t, "parent hash does not match terminal block hash", validateTerminalBlockHash(1, &enginev1.ExecutionPayload{}))
require.NoError(t, validateTerminalBlockHash(1, &enginev1.ExecutionPayload{ParentHash: cfg.TerminalBlockHash.Bytes()}))
}

View File

@@ -27,6 +27,7 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/operations/voluntaryexits"
"github.com/prysmaticlabs/prysm/beacon-chain/p2p"
"github.com/prysmaticlabs/prysm/beacon-chain/powchain"
enginev1 "github.com/prysmaticlabs/prysm/beacon-chain/powchain/engine-api-client/v1"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
"github.com/prysmaticlabs/prysm/cmd/beacon-chain/flags"
@@ -83,6 +84,7 @@ type config struct {
SlasherAttestationsFeed *event.Feed
WeakSubjectivityCheckpt *ethpb.Checkpoint
FinalizedStateAtStartUp state.BeaconState
ExecutionEngineCaller enginev1.Caller
}
// NewService instantiates a new block service instance that will

View File

@@ -32,34 +32,35 @@ var ErrNilState = errors.New("nil state")
// ChainService defines the mock interface for testing
type ChainService struct {
State state.BeaconState
Root []byte
Block block.SignedBeaconBlock
Optimistic bool
ValidAttestation bool
ValidatorsRoot [32]byte
PublicKey [fieldparams.BLSPubkeyLength]byte
FinalizedCheckPoint *ethpb.Checkpoint
CurrentJustifiedCheckPoint *ethpb.Checkpoint
PreviousJustifiedCheckPoint *ethpb.Checkpoint
BlocksReceived []block.SignedBeaconBlock
Slot *types.Slot // Pointer because 0 is a useful value, so checking against it can be incorrect.
Balance *precompute.Balance
Genesis time.Time
ValidatorsRoot [32]byte
ForkChoiceStore *protoarray.Store
CanonicalRoots map[[32]byte]bool
Fork *ethpb.Fork
ETH1Data *ethpb.Eth1Data
InitSyncBlockRoots map[[32]byte]bool
DB db.Database
State state.BeaconState
Block block.SignedBeaconBlock
VerifyBlkDescendantErr error
stateNotifier statefeed.Notifier
BlocksReceived []block.SignedBeaconBlock
SyncCommitteeIndices []types.CommitteeIndex
blockNotifier blockfeed.Notifier
opNotifier opfeed.Notifier
ValidAttestation bool
ForkChoiceStore *protoarray.Store
VerifyBlkDescendantErr error
Slot *types.Slot // Pointer because 0 is a useful value, so checking against it can be incorrect.
SyncCommitteeIndices []types.CommitteeIndex
Root []byte
SyncCommitteeDomain []byte
SyncSelectionProofDomain []byte
SyncContributionProofDomain []byte
PublicKey [fieldparams.BLSPubkeyLength]byte
SyncCommitteePubkeys [][]byte
InitSyncBlockRoots map[[32]byte]bool
Genesis time.Time
}
// StateNotifier mocks the same method in the chain service.
@@ -442,7 +443,7 @@ func (s *ChainService) HeadSyncContributionProofDomain(_ context.Context, _ type
// IsOptimistic mocks the same method in the chain service.
func (s *ChainService) IsOptimistic(_ context.Context) (bool, error) {
return false, nil
return s.Optimistic, nil
}
// IsOptimisticForRoot mocks the same method in the chain service.

View File

@@ -124,8 +124,8 @@ func ValidatePayload(st state.BeaconState, payload *enginev1.ExecutionPayload) e
return err
}
if !bytes.Equal(payload.Random, random) {
return errors.New("incorrect random")
if !bytes.Equal(payload.PrevRandao, random) {
return errors.New("incorrect prev randao")
}
t, err := slots.ToTime(st.GenesisTime(), st.Slot())
if err != nil {
@@ -201,7 +201,7 @@ func PayloadToHeader(payload *enginev1.ExecutionPayload) (*ethpb.ExecutionPayloa
StateRoot: bytesutil.SafeCopyBytes(payload.StateRoot),
ReceiptRoot: bytesutil.SafeCopyBytes(payload.ReceiptsRoot),
LogsBloom: bytesutil.SafeCopyBytes(payload.LogsBloom),
Random: bytesutil.SafeCopyBytes(payload.Random),
PrevRandao: bytesutil.SafeCopyBytes(payload.PrevRandao),
BlockNumber: payload.BlockNumber,
GasLimit: payload.GasLimit,
GasUsed: payload.GasUsed,
@@ -229,7 +229,7 @@ func isEmptyPayload(p *enginev1.ExecutionPayload) bool {
if !bytes.Equal(p.LogsBloom, make([]byte, fieldparams.LogsBloomLength)) {
return false
}
if !bytes.Equal(p.Random, make([]byte, fieldparams.RootLength)) {
if !bytes.Equal(p.PrevRandao, make([]byte, fieldparams.RootLength)) {
return false
}
if !bytes.Equal(p.BaseFeePerGas, make([]byte, fieldparams.RootLength)) {
@@ -275,7 +275,7 @@ func isEmptyHeader(h *ethpb.ExecutionPayloadHeader) bool {
if !bytes.Equal(h.LogsBloom, make([]byte, fieldparams.LogsBloomLength)) {
return false
}
if !bytes.Equal(h.Random, make([]byte, fieldparams.RootLength)) {
if !bytes.Equal(h.PrevRandao, make([]byte, fieldparams.RootLength)) {
return false
}
if !bytes.Equal(h.BaseFeePerGas, make([]byte, fieldparams.RootLength)) {

View File

@@ -78,7 +78,7 @@ func Test_MergeComplete(t *testing.T) {
name: "has random",
payload: func() *ethpb.ExecutionPayloadHeader {
h := emptyPayloadHeader()
h.Random = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
h.PrevRandao = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
return h
}(),
want: true,
@@ -246,7 +246,7 @@ func Test_MergeBlock(t *testing.T) {
name: "empty header, payload has random",
payload: func() *enginev1.ExecutionPayload {
p := emptyPayload()
p.Random = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
p.PrevRandao = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
return p
}(),
header: emptyPayloadHeader(),
@@ -520,21 +520,21 @@ func Test_ValidatePayload(t *testing.T) {
name: "validate passes",
payload: func() *enginev1.ExecutionPayload {
h := emptyPayload()
h.Random = random
h.PrevRandao = random
h.Timestamp = uint64(ts.Unix())
return h
}(), err: nil,
},
{
name: "incorrect random",
name: "incorrect prev randao",
payload: emptyPayload(),
err: errors.New("incorrect random"),
err: errors.New("incorrect prev randao"),
},
{
name: "incorrect timestamp",
payload: func() *enginev1.ExecutionPayload {
h := emptyPayload()
h.Random = random
h.PrevRandao = random
h.Timestamp = 1
return h
}(),
@@ -568,21 +568,21 @@ func Test_ProcessPayload(t *testing.T) {
name: "process passes",
payload: func() *enginev1.ExecutionPayload {
h := emptyPayload()
h.Random = random
h.PrevRandao = random
h.Timestamp = uint64(ts.Unix())
return h
}(), err: nil,
},
{
name: "incorrect random",
name: "incorrect prev randao",
payload: emptyPayload(),
err: errors.New("incorrect random"),
err: errors.New("incorrect prev randao"),
},
{
name: "incorrect timestamp",
payload: func() *enginev1.ExecutionPayload {
h := emptyPayload()
h.Random = random
h.PrevRandao = random
h.Timestamp = 1
return h
}(),
@@ -621,7 +621,7 @@ func Test_PayloadToHeader(t *testing.T) {
p.StateRoot = b
p.ReceiptsRoot = b
p.LogsBloom = b
p.Random = b
p.PrevRandao = b
p.ExtraData = b
p.BaseFeePerGas = b
p.BlockHash = b
@@ -635,7 +635,7 @@ func Test_PayloadToHeader(t *testing.T) {
require.DeepSSZEqual(t, h.StateRoot, make([]byte, fieldparams.RootLength))
require.DeepSSZEqual(t, h.ReceiptRoot, make([]byte, fieldparams.RootLength))
require.DeepSSZEqual(t, h.LogsBloom, make([]byte, fieldparams.LogsBloomLength))
require.DeepSSZEqual(t, h.Random, make([]byte, fieldparams.RootLength))
require.DeepSSZEqual(t, h.PrevRandao, make([]byte, fieldparams.RootLength))
require.DeepSSZEqual(t, h.ExtraData, make([]byte, 0))
require.DeepSSZEqual(t, h.BaseFeePerGas, make([]byte, fieldparams.RootLength))
require.DeepSSZEqual(t, h.BlockHash, make([]byte, fieldparams.RootLength))
@@ -663,7 +663,7 @@ func emptyPayloadHeader() *ethpb.ExecutionPayloadHeader {
StateRoot: make([]byte, fieldparams.RootLength),
ReceiptRoot: make([]byte, fieldparams.RootLength),
LogsBloom: make([]byte, fieldparams.LogsBloomLength),
Random: make([]byte, fieldparams.RootLength),
PrevRandao: make([]byte, fieldparams.RootLength),
BaseFeePerGas: make([]byte, fieldparams.RootLength),
BlockHash: make([]byte, fieldparams.RootLength),
TransactionsRoot: make([]byte, fieldparams.RootLength),
@@ -678,7 +678,7 @@ func emptyPayload() *enginev1.ExecutionPayload {
StateRoot: make([]byte, fieldparams.RootLength),
ReceiptsRoot: make([]byte, fieldparams.RootLength),
LogsBloom: make([]byte, fieldparams.LogsBloomLength),
Random: make([]byte, fieldparams.RootLength),
PrevRandao: make([]byte, fieldparams.RootLength),
BaseFeePerGas: make([]byte, fieldparams.RootLength),
BlockHash: make([]byte, fieldparams.RootLength),
Transactions: make([][]byte, 0),

View File

@@ -71,7 +71,7 @@ func UpgradeToBellatrix(ctx context.Context, state state.BeaconState) (state.Bea
StateRoot: make([]byte, 32),
ReceiptRoot: make([]byte, 32),
LogsBloom: make([]byte, 256),
Random: make([]byte, 32),
PrevRandao: make([]byte, 32),
BlockNumber: 0,
GasLimit: 0,
GasUsed: 0,

View File

@@ -67,7 +67,7 @@ func TestUpgradeToBellatrix(t *testing.T) {
StateRoot: make([]byte, 32),
ReceiptRoot: make([]byte, 32),
LogsBloom: make([]byte, 256),
Random: make([]byte, 32),
PrevRandao: make([]byte, 32),
BlockNumber: 0,
GasLimit: 0,
GasUsed: 0,

View File

@@ -244,7 +244,7 @@ func createFullBellatrixBlockWithOperations(t *testing.T) (state.BeaconState,
StateRoot: make([]byte, fieldparams.RootLength),
ReceiptsRoot: make([]byte, fieldparams.RootLength),
LogsBloom: make([]byte, fieldparams.LogsBloomLength),
Random: make([]byte, fieldparams.RootLength),
PrevRandao: make([]byte, fieldparams.RootLength),
BaseFeePerGas: make([]byte, fieldparams.RootLength),
BlockHash: make([]byte, fieldparams.RootLength),
Transactions: make([][]byte, 0),

View File

@@ -47,6 +47,7 @@ func (f *ForkChoice) Optimistic(ctx context.Context, root [32]byte, slot types.S
f.syncedTips.RLock()
_, ok := f.syncedTips.validatedTips[root]
if ok {
f.syncedTips.RUnlock()
return false, nil
}
f.syncedTips.RUnlock()

View File

@@ -200,6 +200,10 @@ func TestOptimistic(t *testing.T) {
op, err = f.Optimistic(ctx, nodeK.root, nodeK.slot)
require.NoError(t, err)
require.Equal(t, op, true)
// request a write Lock to synced Tips regression #10289
f.syncedTips.Lock()
defer f.syncedTips.Unlock()
}
// This tests the algorithm to update syncedTips

View File

@@ -834,6 +834,7 @@ func (b *BeaconNode) registerGRPCGateway() error {
selfCert := b.cliCtx.String(flags.CertFlag.Name)
maxCallSize := b.cliCtx.Uint64(cmd.GrpcMaxCallRecvMsgSizeFlag.Name)
httpModules := b.cliCtx.String(flags.HTTPModules.Name)
timeout := b.cliCtx.Int(cmd.ApiTimeoutFlag.Name)
if enableDebugRPCEndpoints {
maxCallSize = uint64(math.Max(float64(maxCallSize), debugGrpcMaxMsgSize))
}
@@ -855,6 +856,7 @@ func (b *BeaconNode) registerGRPCGateway() error {
apigateway.WithRemoteCert(selfCert),
apigateway.WithMaxCallRecvMsgSize(maxCallSize),
apigateway.WithAllowedOrigins(allowedOrigins),
apigateway.WithTimeout(uint64(timeout)),
}
if flags.EnableHTTPEthAPI(httpModules) {
opts = append(opts, apigateway.WithApiMiddleware(&apimiddleware.BeaconEndpointFactory{}))

View File

@@ -5,6 +5,7 @@ go_library(
srcs = [
"block_cache.go",
"block_reader.go",
"check_transition_config.go",
"deposit.go",
"log.go",
"log_processing.go",
@@ -44,6 +45,7 @@ go_library(
"//monitoring/tracing:go_default_library",
"//network:go_default_library",
"//network/authorization:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//time:go_default_library",
"//time/slots:go_default_library",
@@ -54,6 +56,7 @@ go_library(
"@com_github_ethereum_go_ethereum//core/types:go_default_library",
"@com_github_ethereum_go_ethereum//ethclient: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",
"@com_github_prometheus_client_golang//prometheus:go_default_library",
"@com_github_prometheus_client_golang//prometheus/promauto:go_default_library",
@@ -69,6 +72,7 @@ go_test(
srcs = [
"block_cache_test.go",
"block_reader_test.go",
"check_transition_config_test.go",
"deposit_test.go",
"init_test.go",
"log_processing_test.go",
@@ -87,6 +91,8 @@ go_test(
"//beacon-chain/core/signing:go_default_library",
"//beacon-chain/db:go_default_library",
"//beacon-chain/db/testing:go_default_library",
"//beacon-chain/powchain/engine-api-client/v1:go_default_library",
"//beacon-chain/powchain/engine-api-client/v1/mocks:go_default_library",
"//beacon-chain/powchain/testing:go_default_library",
"//beacon-chain/powchain/types:go_default_library",
"//beacon-chain/state/stategen:go_default_library",

View File

@@ -0,0 +1,82 @@
package powchain
import (
"context"
"errors"
"math/big"
"time"
"github.com/holiman/uint256"
v1 "github.com/prysmaticlabs/prysm/beacon-chain/powchain/engine-api-client/v1"
"github.com/prysmaticlabs/prysm/config/params"
pb "github.com/prysmaticlabs/prysm/proto/engine/v1"
)
var (
checkTransitionPollingInterval = time.Second * 10
configMismatchLog = "Configuration mismatch between your execution client and Prysm. " +
"Please check your execution client and restart it with the proper configuration. If this is not done, " +
"your node will not be able to complete the proof-of-stake transition"
)
// Checks the transition configuration between Prysm and the connected execution node to ensure
// there are no differences in terminal block difficulty and block hash.
// If there are any discrepancies, we must log errors to ensure users can resolve
//the problem and be ready for the merge transition.
func (s *Service) checkTransitionConfiguration(ctx context.Context) {
if s.engineAPIClient == nil {
return
}
i := new(big.Int)
i.SetString(params.BeaconConfig().TerminalTotalDifficulty, 10)
ttd := new(uint256.Int)
ttd.SetFromBig(i)
cfg := &pb.TransitionConfiguration{
TerminalTotalDifficulty: ttd.Hex(),
TerminalBlockHash: params.BeaconConfig().TerminalBlockHash[:],
TerminalBlockNumber: big.NewInt(0).Bytes(), // A value of 0 is recommended in the request.
}
err := s.engineAPIClient.ExchangeTransitionConfiguration(ctx, cfg)
if err != nil {
if errors.Is(err, v1.ErrConfigMismatch) {
log.WithError(err).Fatal(configMismatchLog)
}
log.WithError(err).Error("Could not check configuration values between execution and consensus client")
}
// We poll the execution client to see if the transition configuration has changed.
// This serves as a heartbeat to ensure the execution client and Prysm are ready for the
// Bellatrix hard-fork transition.
ticker := time.NewTicker(checkTransitionPollingInterval)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
err = s.engineAPIClient.ExchangeTransitionConfiguration(ctx, cfg)
s.handleExchangeConfigurationError(err)
}
}
}
// We check if there is a configuration mismatch error between the execution client
// and the Prysm beacon node. If so, we need to log errors in the node as it cannot successfully
// complete the merge transition for the Bellatrix hard fork.
func (s *Service) handleExchangeConfigurationError(err error) {
if err == nil {
// If there is no error in checking the exchange configuration error, we clear
// the run error of the service if we had previously set it to ErrConfigMismatch.
if errors.Is(s.runError, v1.ErrConfigMismatch) {
s.runError = nil
}
return
}
// If the error is a configuration mismatch, we set a runtime error in the service.
if errors.Is(err, v1.ErrConfigMismatch) {
s.runError = err
log.WithError(err).Error(configMismatchLog)
return
}
log.WithError(err).Error("Could not check configuration values between execution and consensus client")
}

View File

@@ -0,0 +1,59 @@
package powchain
import (
"context"
"errors"
"testing"
"time"
v1 "github.com/prysmaticlabs/prysm/beacon-chain/powchain/engine-api-client/v1"
"github.com/prysmaticlabs/prysm/beacon-chain/powchain/engine-api-client/v1/mocks"
"github.com/prysmaticlabs/prysm/testing/require"
logTest "github.com/sirupsen/logrus/hooks/test"
)
func Test_checkTransitionConfiguration(t *testing.T) {
ctx := context.Background()
hook := logTest.NewGlobal()
m := &mocks.EngineClient{}
m.Err = errors.New("something went wrong")
srv := &Service{}
srv.engineAPIClient = m
checkTransitionPollingInterval = time.Millisecond
ctx, cancel := context.WithCancel(ctx)
go srv.checkTransitionConfiguration(ctx)
<-time.After(100 * time.Millisecond)
cancel()
require.LogsContain(t, hook, "Could not check configuration values")
}
func TestService_handleExchangeConfigurationError(t *testing.T) {
hook := logTest.NewGlobal()
t.Run("clears existing service error", func(t *testing.T) {
srv := &Service{isRunning: true}
srv.runError = v1.ErrConfigMismatch
srv.handleExchangeConfigurationError(nil)
require.Equal(t, true, srv.Status() == nil)
})
t.Run("does not clear existing service error if wrong kind", func(t *testing.T) {
srv := &Service{isRunning: true}
err := errors.New("something else went wrong")
srv.runError = err
srv.handleExchangeConfigurationError(nil)
require.ErrorIs(t, err, srv.Status())
})
t.Run("sets service error on config mismatch", func(t *testing.T) {
srv := &Service{isRunning: true}
srv.handleExchangeConfigurationError(v1.ErrConfigMismatch)
require.Equal(t, v1.ErrConfigMismatch, srv.Status())
require.LogsContain(t, hook, configMismatchLog)
})
t.Run("does not set service error if unrelated problem", func(t *testing.T) {
srv := &Service{isRunning: true}
srv.handleExchangeConfigurationError(errors.New("foo"))
require.Equal(t, true, srv.Status() == nil)
require.LogsContain(t, hook, "Could not check configuration values")
})
}

View File

@@ -3,6 +3,7 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = [
"auth.go",
"client.go",
"errors.go",
"options.go",
@@ -13,16 +14,22 @@ go_library(
"//config/params:go_default_library",
"//proto/engine/v1: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//rpc:go_default_library",
"@com_github_golang_jwt_jwt_v4//:go_default_library",
"@com_github_pkg_errors//:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["client_test.go"],
srcs = [
"auth_test.go",
"client_test.go",
],
embed = [":go_default_library"],
deps = [
"//beacon-chain/powchain/engine-api-client/v1/mocks:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//encoding/bytesutil:go_default_library",
@@ -30,6 +37,8 @@ go_test(
"//testing/require:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_ethereum_go_ethereum//rpc:go_default_library",
"@com_github_golang_jwt_jwt_v4//:go_default_library",
"@com_github_holiman_uint256//:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@org_golang_google_protobuf//proto:go_default_library",
],

View File

@@ -0,0 +1,44 @@
package v1
import (
"net/http"
"time"
"github.com/golang-jwt/jwt/v4"
"github.com/pkg/errors"
)
// This creates a custom HTTP transport which we can attach to our HTTP client
// in order to inject JWT auth strings into our HTTP request headers. Authentication
// is required when interacting with an Ethereum engine API server via HTTP, and JWT
// is chosen as the scheme of choice.
// For more details on the requirements of authentication when using the engine API, see
// the specification here: https://github.com/ethereum/execution-apis/blob/main/src/engine/authentication.md
//
// To use this transport, initialize a new &http.Client{} from the standard library
// and set the Transport field to &jwtTransport{} with values
// http.DefaultTransport and a JWT secret.
type jwtTransport struct {
underlyingTransport http.RoundTripper
jwtSecret []byte
}
// RoundTrip ensures our transport implements http.RoundTripper interface from the
// standard library. When used as the transport for an HTTP client, the code below
// will run every time our client makes an HTTP request. This is used to inject
// an JWT bearer token in the Authorization request header of every outgoing request
// our HTTP client makes.
func (t *jwtTransport) RoundTrip(req *http.Request) (*http.Response, error) {
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
// Required claim for engine API auth. "iat" stands for issued at
// and it must be a unix timestamp that is +/- 5 seconds from the current
// timestamp at the moment the server verifies this value.
"iat": time.Now().Unix(),
})
tokenString, err := token.SignedString(t.jwtSecret)
if err != nil {
return nil, errors.Wrap(err, "could not produce signed JWT token")
}
req.Header.Set("Authorization", "Bearer "+tokenString)
return t.underlyingTransport.RoundTrip(req)
}

View File

@@ -0,0 +1,53 @@
package v1
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
"github.com/golang-jwt/jwt/v4"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/testing/require"
)
func TestJWTAuthTransport(t *testing.T) {
secret := bytesutil.PadTo([]byte("foo"), 32)
authTransport := &jwtTransport{
underlyingTransport: http.DefaultTransport,
jwtSecret: secret,
}
client := &http.Client{
Timeout: DefaultTimeout,
Transport: authTransport,
}
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
reqToken := r.Header.Get("Authorization")
splitToken := strings.Split(reqToken, "Bearer")
// The format should be `Bearer ${token}`.
require.Equal(t, 2, len(splitToken))
reqToken = strings.TrimSpace(splitToken[1])
token, err := jwt.Parse(reqToken, func(token *jwt.Token) (interface{}, error) {
// We should be doing HMAC signing.
_, ok := token.Method.(*jwt.SigningMethodHMAC)
require.Equal(t, true, ok)
return secret, nil
})
require.NoError(t, err)
require.Equal(t, true, token.Valid)
claims, ok := token.Claims.(jwt.MapClaims)
require.Equal(t, true, ok)
item, ok := claims["iat"]
require.Equal(t, true, ok)
iat, ok := item.(float64)
require.Equal(t, true, ok)
issuedAt := time.Unix(int64(iat), 0)
// The claims should have an "iat" field (issued at) that is at most, 5 seconds ago.
since := time.Since(issuedAt)
require.Equal(t, true, since <= time.Second*5)
}))
defer srv.Close()
_, err := client.Get(srv.URL)
require.NoError(t, err)
}

View File

@@ -6,11 +6,13 @@ package v1
import (
"bytes"
"context"
"fmt"
"math/big"
"net/url"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/rpc"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/config/params"
@@ -41,17 +43,17 @@ type ForkchoiceUpdatedResponse struct {
PayloadId *pb.PayloadIDBytes `json:"payloadId"`
}
// EngineCaller defines a client that can interact with an Ethereum
// Caller defines a client that can interact with an Ethereum
// execution node's engine service via JSON-RPC.
type EngineCaller interface {
NewPayload(ctx context.Context, payload *pb.ExecutionPayload) (*pb.PayloadStatus, error)
type Caller interface {
NewPayload(ctx context.Context, payload *pb.ExecutionPayload) ([]byte, error)
ForkchoiceUpdated(
ctx context.Context, state *pb.ForkchoiceState, attrs *pb.PayloadAttributes,
) (*ForkchoiceUpdatedResponse, error)
) (*pb.PayloadIDBytes, []byte, error)
GetPayload(ctx context.Context, payloadId [8]byte) (*pb.ExecutionPayload, error)
ExchangeTransitionConfiguration(
ctx context.Context, cfg *pb.TransitionConfiguration,
) (*pb.TransitionConfiguration, error)
) error
LatestExecutionBlock(ctx context.Context) (*pb.ExecutionBlock, error)
ExecutionBlockByHash(ctx context.Context, hash common.Hash) (*pb.ExecutionBlock, error)
}
@@ -73,6 +75,11 @@ func New(ctx context.Context, endpoint string, opts ...Option) (*Client, error)
c := &Client{
cfg: defaultConfig(),
}
for _, opt := range opts {
if err := opt(c); err != nil {
return nil, err
}
}
switch u.Scheme {
case "http", "https":
c.rpc, err = rpc.DialHTTPWithClient(endpoint, c.cfg.httpClient)
@@ -84,28 +91,59 @@ func New(ctx context.Context, endpoint string, opts ...Option) (*Client, error)
if err != nil {
return nil, err
}
for _, opt := range opts {
if err := opt(c); err != nil {
return nil, err
}
}
return c, nil
}
// NewPayload calls the engine_newPayloadV1 method via JSON-RPC.
func (c *Client) NewPayload(ctx context.Context, payload *pb.ExecutionPayload) (*pb.PayloadStatus, error) {
func (c *Client) NewPayload(ctx context.Context, payload *pb.ExecutionPayload) ([]byte, error) {
result := &pb.PayloadStatus{}
err := c.rpc.CallContext(ctx, result, NewPayloadMethod, payload)
return result, handleRPCError(err)
if err != nil {
return nil, handleRPCError(err)
}
switch result.Status {
case pb.PayloadStatus_INVALID_BLOCK_HASH:
return nil, fmt.Errorf("could not validate block hash: %v", result.ValidationError)
case pb.PayloadStatus_INVALID_TERMINAL_BLOCK:
return nil, fmt.Errorf("could not satisfy terminal block condition: %v", result.ValidationError)
case pb.PayloadStatus_ACCEPTED, pb.PayloadStatus_SYNCING:
return nil, ErrAcceptedSyncingPayloadStatus
case pb.PayloadStatus_INVALID:
return result.LatestValidHash, ErrInvalidPayloadStatus
case pb.PayloadStatus_VALID:
return result.LatestValidHash, nil
default:
return nil, ErrUnknownPayloadStatus
}
}
// ForkchoiceUpdated calls the engine_forkchoiceUpdatedV1 method via JSON-RPC.
func (c *Client) ForkchoiceUpdated(
ctx context.Context, state *pb.ForkchoiceState, attrs *pb.PayloadAttributes,
) (*ForkchoiceUpdatedResponse, error) {
) (*pb.PayloadIDBytes, []byte, error) {
result := &ForkchoiceUpdatedResponse{}
err := c.rpc.CallContext(ctx, result, ForkchoiceUpdatedMethod, state, attrs)
return result, handleRPCError(err)
if err != nil {
return nil, nil, handleRPCError(err)
}
if result.Status == nil {
return nil, nil, ErrNilResponse
}
resp := result.Status
switch resp.Status {
case pb.PayloadStatus_INVALID_TERMINAL_BLOCK:
return nil, nil, fmt.Errorf("could not satisfy terminal block condition: %v", resp.ValidationError)
case pb.PayloadStatus_SYNCING:
return nil, nil, ErrAcceptedSyncingPayloadStatus
case pb.PayloadStatus_INVALID:
return nil, resp.LatestValidHash, ErrInvalidPayloadStatus
case pb.PayloadStatus_VALID:
return result.PayloadId, resp.LatestValidHash, nil
default:
return nil, nil, ErrUnknownPayloadStatus
}
}
// GetPayload calls the engine_getPayloadV1 method via JSON-RPC.
@@ -118,35 +156,39 @@ func (c *Client) GetPayload(ctx context.Context, payloadId [8]byte) (*pb.Executi
// ExchangeTransitionConfiguration calls the engine_exchangeTransitionConfigurationV1 method via JSON-RPC.
func (c *Client) ExchangeTransitionConfiguration(
ctx context.Context, cfg *pb.TransitionConfiguration,
) (*pb.TransitionConfiguration, error) {
// Terminal block number should be set to 0
) error {
// We set terminal block number to 0 as the parameter is not set on the consensus layer.
zeroBigNum := big.NewInt(0)
cfg.TerminalBlockNumber = zeroBigNum.Bytes()
result := &pb.TransitionConfiguration{}
if err := c.rpc.CallContext(ctx, result, ExchangeTransitionConfigurationMethod, cfg); err != nil {
return nil, handleRPCError(err)
return handleRPCError(err)
}
// We surface an error to the user if local configuration settings mismatch
// according to the response from the execution node.
cfgTerminalHash := params.BeaconConfig().TerminalBlockHash[:]
if !bytes.Equal(cfgTerminalHash, result.TerminalBlockHash) {
return nil, errors.Wrapf(
ErrMismatchTerminalBlockHash,
return errors.Wrapf(
ErrConfigMismatch,
"got %#x from execution node, wanted %#x",
result.TerminalBlockHash,
cfgTerminalHash,
)
}
ttdCfg := params.BeaconConfig().TerminalTotalDifficulty
if ttdCfg != result.TerminalTotalDifficulty {
return nil, errors.Wrapf(
ErrMismatchTerminalTotalDiff,
ttdResult, err := hexutil.DecodeBig(result.TerminalTotalDifficulty)
if err != nil {
return errors.Wrap(err, "could not decode received terminal total difficulty")
}
if ttdResult.String() != ttdCfg {
return errors.Wrapf(
ErrConfigMismatch,
"got %s from execution node, wanted %s",
result.TerminalTotalDifficulty,
ttdResult.String(),
ttdCfg,
)
}
return result, nil
return nil
}
// LatestExecutionBlock fetches the latest execution engine block by calling

View File

@@ -13,7 +13,9 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rpc"
"github.com/holiman/uint256"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/beacon-chain/powchain/engine-api-client/v1/mocks"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
@@ -22,7 +24,10 @@ import (
"google.golang.org/protobuf/proto"
)
var _ = EngineCaller(&Client{})
var (
_ = Caller(&Client{})
_ = Caller(&mocks.EngineClient{})
)
func TestClient_IPC(t *testing.T) {
server := newTestIPCServer(t)
@@ -45,35 +50,25 @@ func TestClient_IPC(t *testing.T) {
t.Run(ForkchoiceUpdatedMethod, func(t *testing.T) {
want, ok := fix["ForkchoiceUpdatedResponse"].(*ForkchoiceUpdatedResponse)
require.Equal(t, true, ok)
resp, err := client.ForkchoiceUpdated(ctx, &pb.ForkchoiceState{}, &pb.PayloadAttributes{})
payloadID, validHash, err := client.ForkchoiceUpdated(ctx, &pb.ForkchoiceState{}, &pb.PayloadAttributes{})
require.NoError(t, err)
require.DeepEqual(t, want.Status, resp.Status)
require.DeepEqual(t, want.PayloadId, resp.PayloadId)
require.DeepEqual(t, want.Status.LatestValidHash, validHash)
require.DeepEqual(t, want.PayloadId, payloadID)
})
t.Run(NewPayloadMethod, func(t *testing.T) {
want, ok := fix["PayloadStatus"].(*pb.PayloadStatus)
want, ok := fix["ValidPayloadStatus"].(*pb.PayloadStatus)
require.Equal(t, true, ok)
req, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
require.Equal(t, true, ok)
resp, err := client.NewPayload(ctx, req)
latestValidHash, err := client.NewPayload(ctx, req)
require.NoError(t, err)
require.DeepEqual(t, want, resp)
})
t.Run(NewPayloadMethod, func(t *testing.T) {
want, ok := fix["PayloadStatus"].(*pb.PayloadStatus)
require.Equal(t, true, ok)
req, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
require.Equal(t, true, ok)
resp, err := client.NewPayload(ctx, req)
require.NoError(t, err)
require.DeepEqual(t, want, resp)
require.DeepEqual(t, bytesutil.ToBytes32(want.LatestValidHash), bytesutil.ToBytes32(latestValidHash))
})
t.Run(ExchangeTransitionConfigurationMethod, func(t *testing.T) {
want, ok := fix["TransitionConfiguration"].(*pb.TransitionConfiguration)
require.Equal(t, true, ok)
resp, err := client.ExchangeTransitionConfiguration(ctx, want)
err := client.ExchangeTransitionConfiguration(ctx, want)
require.NoError(t, err)
require.DeepEqual(t, want, resp)
})
t.Run(ExecutionBlockByNumberMethod, func(t *testing.T) {
want, ok := fix["ExecutionBlock"].(*pb.ExecutionBlock)
@@ -138,7 +133,7 @@ func TestClient_HTTP(t *testing.T) {
require.NoError(t, err)
require.DeepEqual(t, want, resp)
})
t.Run(ForkchoiceUpdatedMethod, func(t *testing.T) {
t.Run(ForkchoiceUpdatedMethod+" VALID status", func(t *testing.T) {
forkChoiceState := &pb.ForkchoiceState{
HeadBlockHash: []byte("head"),
SafeBlockHash: []byte("safe"),
@@ -146,98 +141,174 @@ func TestClient_HTTP(t *testing.T) {
}
payloadAttributes := &pb.PayloadAttributes{
Timestamp: 1,
Random: []byte("random"),
PrevRandao: []byte("random"),
SuggestedFeeRecipient: []byte("suggestedFeeRecipient"),
}
want, ok := fix["ForkchoiceUpdatedResponse"].(*ForkchoiceUpdatedResponse)
require.Equal(t, true, ok)
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
defer func() {
require.NoError(t, r.Body.Close())
}()
enc, err := ioutil.ReadAll(r.Body)
require.NoError(t, err)
jsonRequestString := string(enc)
forkChoiceStateReq, err := json.Marshal(forkChoiceState)
require.NoError(t, err)
payloadAttrsReq, err := json.Marshal(payloadAttributes)
require.NoError(t, err)
// We expect the JSON string RPC request contains the right arguments.
require.Equal(t, true, strings.Contains(
jsonRequestString, string(forkChoiceStateReq),
))
require.Equal(t, true, strings.Contains(
jsonRequestString, string(payloadAttrsReq),
))
resp := map[string]interface{}{
"jsonrpc": "2.0",
"id": 1,
"result": want,
}
err = json.NewEncoder(w).Encode(resp)
require.NoError(t, err)
}))
defer srv.Close()
rpcClient, err := rpc.DialHTTP(srv.URL)
require.NoError(t, err)
defer rpcClient.Close()
client := &Client{}
client.rpc = rpcClient
client := forkchoiceUpdateSetup(t, forkChoiceState, payloadAttributes, want)
// We call the RPC method via HTTP and expect a proper result.
resp, err := client.ForkchoiceUpdated(ctx, forkChoiceState, payloadAttributes)
payloadID, validHash, err := client.ForkchoiceUpdated(ctx, forkChoiceState, payloadAttributes)
require.NoError(t, err)
require.DeepEqual(t, want.Status, resp.Status)
require.DeepEqual(t, want.PayloadId, resp.PayloadId)
require.DeepEqual(t, want.Status.LatestValidHash, validHash)
require.DeepEqual(t, want.PayloadId, payloadID)
})
t.Run(NewPayloadMethod, func(t *testing.T) {
t.Run(ForkchoiceUpdatedMethod+" SYNCING status", func(t *testing.T) {
forkChoiceState := &pb.ForkchoiceState{
HeadBlockHash: []byte("head"),
SafeBlockHash: []byte("safe"),
FinalizedBlockHash: []byte("finalized"),
}
payloadAttributes := &pb.PayloadAttributes{
Timestamp: 1,
PrevRandao: []byte("random"),
SuggestedFeeRecipient: []byte("suggestedFeeRecipient"),
}
want, ok := fix["ForkchoiceUpdatedSyncingResponse"].(*ForkchoiceUpdatedResponse)
require.Equal(t, true, ok)
client := forkchoiceUpdateSetup(t, forkChoiceState, payloadAttributes, want)
// We call the RPC method via HTTP and expect a proper result.
payloadID, validHash, err := client.ForkchoiceUpdated(ctx, forkChoiceState, payloadAttributes)
require.ErrorIs(t, err, ErrAcceptedSyncingPayloadStatus)
require.DeepEqual(t, (*pb.PayloadIDBytes)(nil), payloadID)
require.DeepEqual(t, []byte(nil), validHash)
})
t.Run(ForkchoiceUpdatedMethod+" INVALID status", func(t *testing.T) {
forkChoiceState := &pb.ForkchoiceState{
HeadBlockHash: []byte("head"),
SafeBlockHash: []byte("safe"),
FinalizedBlockHash: []byte("finalized"),
}
payloadAttributes := &pb.PayloadAttributes{
Timestamp: 1,
PrevRandao: []byte("random"),
SuggestedFeeRecipient: []byte("suggestedFeeRecipient"),
}
want, ok := fix["ForkchoiceUpdatedInvalidResponse"].(*ForkchoiceUpdatedResponse)
require.Equal(t, true, ok)
client := forkchoiceUpdateSetup(t, forkChoiceState, payloadAttributes, want)
// We call the RPC method via HTTP and expect a proper result.
payloadID, validHash, err := client.ForkchoiceUpdated(ctx, forkChoiceState, payloadAttributes)
require.ErrorIs(t, err, ErrInvalidPayloadStatus)
require.DeepEqual(t, (*pb.PayloadIDBytes)(nil), payloadID)
require.DeepEqual(t, want.Status.LatestValidHash, validHash)
})
t.Run(ForkchoiceUpdatedMethod+" UNKNOWN status", func(t *testing.T) {
forkChoiceState := &pb.ForkchoiceState{
HeadBlockHash: []byte("head"),
SafeBlockHash: []byte("safe"),
FinalizedBlockHash: []byte("finalized"),
}
payloadAttributes := &pb.PayloadAttributes{
Timestamp: 1,
PrevRandao: []byte("random"),
SuggestedFeeRecipient: []byte("suggestedFeeRecipient"),
}
want, ok := fix["ForkchoiceUpdatedAcceptedResponse"].(*ForkchoiceUpdatedResponse)
require.Equal(t, true, ok)
client := forkchoiceUpdateSetup(t, forkChoiceState, payloadAttributes, want)
// We call the RPC method via HTTP and expect a proper result.
payloadID, validHash, err := client.ForkchoiceUpdated(ctx, forkChoiceState, payloadAttributes)
require.ErrorIs(t, err, ErrUnknownPayloadStatus)
require.DeepEqual(t, (*pb.PayloadIDBytes)(nil), payloadID)
require.DeepEqual(t, []byte(nil), validHash)
})
t.Run(ForkchoiceUpdatedMethod+" INVALID_TERMINAL_BLOCK status", func(t *testing.T) {
forkChoiceState := &pb.ForkchoiceState{
HeadBlockHash: []byte("head"),
SafeBlockHash: []byte("safe"),
FinalizedBlockHash: []byte("finalized"),
}
payloadAttributes := &pb.PayloadAttributes{
Timestamp: 1,
PrevRandao: []byte("random"),
SuggestedFeeRecipient: []byte("suggestedFeeRecipient"),
}
want, ok := fix["ForkchoiceUpdatedInvalidTerminalBlockResponse"].(*ForkchoiceUpdatedResponse)
require.Equal(t, true, ok)
client := forkchoiceUpdateSetup(t, forkChoiceState, payloadAttributes, want)
// We call the RPC method via HTTP and expect a proper result.
payloadID, validHash, err := client.ForkchoiceUpdated(ctx, forkChoiceState, payloadAttributes)
require.ErrorContains(t, "could not satisfy terminal block condition", err)
require.DeepEqual(t, (*pb.PayloadIDBytes)(nil), payloadID)
require.DeepEqual(t, []byte(nil), validHash)
})
t.Run(NewPayloadMethod+" VALID status", func(t *testing.T) {
execPayload, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
require.Equal(t, true, ok)
want, ok := fix["PayloadStatus"].(*pb.PayloadStatus)
want, ok := fix["ValidPayloadStatus"].(*pb.PayloadStatus)
require.Equal(t, true, ok)
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
defer func() {
require.NoError(t, r.Body.Close())
}()
enc, err := ioutil.ReadAll(r.Body)
require.NoError(t, err)
jsonRequestString := string(enc)
reqArg, err := json.Marshal(execPayload)
require.NoError(t, err)
// We expect the JSON string RPC request contains the right arguments.
require.Equal(t, true, strings.Contains(
jsonRequestString, string(reqArg),
))
resp := map[string]interface{}{
"jsonrpc": "2.0",
"id": 1,
"result": want,
}
err = json.NewEncoder(w).Encode(resp)
require.NoError(t, err)
}))
defer srv.Close()
rpcClient, err := rpc.DialHTTP(srv.URL)
require.NoError(t, err)
defer rpcClient.Close()
client := &Client{}
client.rpc = rpcClient
client := newPayloadSetup(t, want, execPayload)
// We call the RPC method via HTTP and expect a proper result.
resp, err := client.NewPayload(ctx, execPayload)
require.NoError(t, err)
require.DeepEqual(t, want, resp)
require.DeepEqual(t, want.LatestValidHash, resp)
})
t.Run(NewPayloadMethod+" SYNCING status", func(t *testing.T) {
execPayload, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
require.Equal(t, true, ok)
want, ok := fix["SyncingStatus"].(*pb.PayloadStatus)
require.Equal(t, true, ok)
client := newPayloadSetup(t, want, execPayload)
// We call the RPC method via HTTP and expect a proper result.
resp, err := client.NewPayload(ctx, execPayload)
require.ErrorIs(t, ErrAcceptedSyncingPayloadStatus, err)
require.DeepEqual(t, []uint8(nil), resp)
})
t.Run(NewPayloadMethod+" INVALID_BLOCK_HASH status", func(t *testing.T) {
execPayload, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
require.Equal(t, true, ok)
want, ok := fix["InvalidBlockHashStatus"].(*pb.PayloadStatus)
require.Equal(t, true, ok)
client := newPayloadSetup(t, want, execPayload)
// We call the RPC method via HTTP and expect a proper result.
resp, err := client.NewPayload(ctx, execPayload)
require.ErrorContains(t, "could not validate block hash", err)
require.DeepEqual(t, []uint8(nil), resp)
})
t.Run(NewPayloadMethod+" INVALID_TERMINAL_BLOCK status", func(t *testing.T) {
execPayload, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
require.Equal(t, true, ok)
want, ok := fix["InvalidTerminalBlockStatus"].(*pb.PayloadStatus)
require.Equal(t, true, ok)
client := newPayloadSetup(t, want, execPayload)
// We call the RPC method via HTTP and expect a proper result.
resp, err := client.NewPayload(ctx, execPayload)
require.ErrorContains(t, "could not satisfy terminal block condition", err)
require.DeepEqual(t, []uint8(nil), resp)
})
t.Run(NewPayloadMethod+" INVALID status", func(t *testing.T) {
execPayload, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
require.Equal(t, true, ok)
want, ok := fix["InvalidStatus"].(*pb.PayloadStatus)
require.Equal(t, true, ok)
client := newPayloadSetup(t, want, execPayload)
// We call the RPC method via HTTP and expect a proper result.
resp, err := client.NewPayload(ctx, execPayload)
require.ErrorIs(t, ErrInvalidPayloadStatus, err)
require.DeepEqual(t, want.LatestValidHash, resp)
})
t.Run(NewPayloadMethod+" UNKNOWN status", func(t *testing.T) {
execPayload, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
require.Equal(t, true, ok)
want, ok := fix["UnknownStatus"].(*pb.PayloadStatus)
require.Equal(t, true, ok)
client := newPayloadSetup(t, want, execPayload)
// We call the RPC method via HTTP and expect a proper result.
resp, err := client.NewPayload(ctx, execPayload)
require.ErrorIs(t, ErrUnknownPayloadStatus, err)
require.DeepEqual(t, []uint8(nil), resp)
})
t.Run(ExecutionBlockByNumberMethod, func(t *testing.T) {
want, ok := fix["ExecutionBlock"].(*pb.ExecutionBlock)
@@ -304,9 +375,8 @@ func TestClient_HTTP(t *testing.T) {
client.rpc = rpcClient
// We call the RPC method via HTTP and expect a proper result.
resp, err := client.ExchangeTransitionConfiguration(ctx, want)
err = client.ExchangeTransitionConfiguration(ctx, want)
require.NoError(t, err)
require.DeepEqual(t, want, resp)
})
t.Run(ExecutionBlockByHashMethod, func(t *testing.T) {
arg := common.BytesToHash([]byte("foo"))
@@ -382,8 +452,8 @@ func TestExchangeTransitionConfiguration(t *testing.T) {
client := &Client{}
client.rpc = rpcClient
_, err = client.ExchangeTransitionConfiguration(ctx, request)
require.Equal(t, true, errors.Is(err, ErrMismatchTerminalBlockHash))
err = client.ExchangeTransitionConfiguration(ctx, request)
require.Equal(t, true, errors.Is(err, ErrConfigMismatch))
})
t.Run("wrong terminal total difficulty", func(t *testing.T) {
request, ok := fix["TransitionConfiguration"].(*pb.TransitionConfiguration)
@@ -398,7 +468,7 @@ func TestExchangeTransitionConfiguration(t *testing.T) {
}()
// Change the terminal block hash.
resp.TerminalTotalDifficulty = "bar"
resp.TerminalTotalDifficulty = "0x1"
respJSON := map[string]interface{}{
"jsonrpc": "2.0",
"id": 1,
@@ -415,8 +485,8 @@ func TestExchangeTransitionConfiguration(t *testing.T) {
client := &Client{}
client.rpc = rpcClient
_, err = client.ExchangeTransitionConfiguration(ctx, request)
require.Equal(t, true, errors.Is(err, ErrMismatchTerminalTotalDiff))
err = client.ExchangeTransitionConfiguration(ctx, request)
require.Equal(t, true, errors.Is(err, ErrConfigMismatch))
})
}
@@ -533,7 +603,7 @@ func fixtures() map[string]interface{} {
StateRoot: foo[:],
ReceiptsRoot: foo[:],
LogsBloom: baz,
Random: foo[:],
PrevRandao: foo[:],
BlockNumber: 1,
GasLimit: 1,
GasUsed: 1,
@@ -563,7 +633,7 @@ func fixtures() map[string]interface{} {
ReceiptsRoot: receiptsRoot,
LogsBloom: logsBloom,
Difficulty: bytesutil.PadTo([]byte("1"), fieldparams.RootLength),
TotalDifficulty: bytesutil.PadTo([]byte("2"), fieldparams.RootLength),
TotalDifficulty: "2",
GasLimit: 3,
GasUsed: 4,
Timestamp: 5,
@@ -574,7 +644,7 @@ func fixtures() map[string]interface{} {
Uncles: [][]byte{foo[:]},
}
status := &pb.PayloadStatus{
Status: pb.PayloadStatus_ACCEPTED,
Status: pb.PayloadStatus_VALID,
LatestValidHash: foo[:],
ValidationError: "",
}
@@ -583,17 +653,86 @@ func fixtures() map[string]interface{} {
Status: status,
PayloadId: &id,
}
forkChoiceSyncingResp := &ForkchoiceUpdatedResponse{
Status: &pb.PayloadStatus{
Status: pb.PayloadStatus_SYNCING,
LatestValidHash: nil,
},
PayloadId: &id,
}
forkChoiceInvalidTerminalBlockResp := &ForkchoiceUpdatedResponse{
Status: &pb.PayloadStatus{
Status: pb.PayloadStatus_INVALID_TERMINAL_BLOCK,
LatestValidHash: nil,
},
PayloadId: &id,
}
forkChoiceAcceptedResp := &ForkchoiceUpdatedResponse{
Status: &pb.PayloadStatus{
Status: pb.PayloadStatus_ACCEPTED,
LatestValidHash: nil,
},
PayloadId: &id,
}
forkChoiceInvalidResp := &ForkchoiceUpdatedResponse{
Status: &pb.PayloadStatus{
Status: pb.PayloadStatus_INVALID,
LatestValidHash: []byte("latestValidHash"),
},
PayloadId: &id,
}
b, _ := new(big.Int).SetString(params.BeaconConfig().TerminalTotalDifficulty, 10)
ttd, _ := uint256.FromBig(b)
transitionCfg := &pb.TransitionConfiguration{
TerminalBlockHash: params.BeaconConfig().TerminalBlockHash[:],
TerminalTotalDifficulty: params.BeaconConfig().TerminalTotalDifficulty,
TerminalTotalDifficulty: ttd.Hex(),
TerminalBlockNumber: big.NewInt(0).Bytes(),
}
validStatus := &pb.PayloadStatus{
Status: pb.PayloadStatus_VALID,
LatestValidHash: foo[:],
ValidationError: "",
}
inValidBlockHashStatus := &pb.PayloadStatus{
Status: pb.PayloadStatus_INVALID_BLOCK_HASH,
LatestValidHash: nil,
}
inValidTerminalBlockStatus := &pb.PayloadStatus{
Status: pb.PayloadStatus_INVALID_TERMINAL_BLOCK,
LatestValidHash: nil,
}
acceptedStatus := &pb.PayloadStatus{
Status: pb.PayloadStatus_ACCEPTED,
LatestValidHash: nil,
}
syncingStatus := &pb.PayloadStatus{
Status: pb.PayloadStatus_SYNCING,
LatestValidHash: nil,
}
invalidStatus := &pb.PayloadStatus{
Status: pb.PayloadStatus_INVALID,
LatestValidHash: foo[:],
}
unknownStatus := &pb.PayloadStatus{
Status: pb.PayloadStatus_UNKNOWN,
LatestValidHash: foo[:],
}
return map[string]interface{}{
"ExecutionBlock": executionBlock,
"ExecutionPayload": executionPayloadFixture,
"PayloadStatus": status,
"ForkchoiceUpdatedResponse": forkChoiceResp,
"TransitionConfiguration": transitionCfg,
"ExecutionBlock": executionBlock,
"ExecutionPayload": executionPayloadFixture,
"ValidPayloadStatus": validStatus,
"InvalidBlockHashStatus": inValidBlockHashStatus,
"InvalidTerminalBlockStatus": inValidTerminalBlockStatus,
"AcceptedStatus": acceptedStatus,
"SyncingStatus": syncingStatus,
"InvalidStatus": invalidStatus,
"UnknownStatus": unknownStatus,
"ForkchoiceUpdatedResponse": forkChoiceResp,
"ForkchoiceUpdatedSyncingResponse": forkChoiceSyncingResp,
"ForkchoiceUpdatedInvalidTerminalBlockResponse": forkChoiceInvalidTerminalBlockResp,
"ForkchoiceUpdatedAcceptedResponse": forkChoiceAcceptedResp,
"ForkchoiceUpdatedInvalidResponse": forkChoiceInvalidResp,
"TransitionConfiguration": transitionCfg,
}
}
@@ -653,6 +792,7 @@ func (*testEngineService) ForkchoiceUpdatedV1(
if !ok {
panic("not found")
}
item.Status.Status = pb.PayloadStatus_VALID
return item
}
@@ -660,9 +800,83 @@ func (*testEngineService) NewPayloadV1(
_ context.Context, _ *pb.ExecutionPayload,
) *pb.PayloadStatus {
fix := fixtures()
item, ok := fix["PayloadStatus"].(*pb.PayloadStatus)
item, ok := fix["ValidPayloadStatus"].(*pb.PayloadStatus)
if !ok {
panic("not found")
}
return item
}
func forkchoiceUpdateSetup(t *testing.T, fcs *pb.ForkchoiceState, att *pb.PayloadAttributes, res *ForkchoiceUpdatedResponse) *Client {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
defer func() {
require.NoError(t, r.Body.Close())
}()
enc, err := ioutil.ReadAll(r.Body)
require.NoError(t, err)
jsonRequestString := string(enc)
forkChoiceStateReq, err := json.Marshal(fcs)
require.NoError(t, err)
payloadAttrsReq, err := json.Marshal(att)
require.NoError(t, err)
// We expect the JSON string RPC request contains the right arguments.
require.Equal(t, true, strings.Contains(
jsonRequestString, string(forkChoiceStateReq),
))
require.Equal(t, true, strings.Contains(
jsonRequestString, string(payloadAttrsReq),
))
resp := map[string]interface{}{
"jsonrpc": "2.0",
"id": 1,
"result": res,
}
err = json.NewEncoder(w).Encode(resp)
require.NoError(t, err)
}))
rpcClient, err := rpc.DialHTTP(srv.URL)
require.NoError(t, err)
client := &Client{}
client.rpc = rpcClient
return client
}
func newPayloadSetup(t *testing.T, status *pb.PayloadStatus, payload *pb.ExecutionPayload) *Client {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
defer func() {
require.NoError(t, r.Body.Close())
}()
enc, err := ioutil.ReadAll(r.Body)
require.NoError(t, err)
jsonRequestString := string(enc)
reqArg, err := json.Marshal(payload)
require.NoError(t, err)
// We expect the JSON string RPC request contains the right arguments.
require.Equal(t, true, strings.Contains(
jsonRequestString, string(reqArg),
))
resp := map[string]interface{}{
"jsonrpc": "2.0",
"id": 1,
"result": status,
}
err = json.NewEncoder(w).Encode(resp)
require.NoError(t, err)
}))
rpcClient, err := rpc.DialHTTP(srv.URL)
require.NoError(t, err)
client := &Client{}
client.rpc = rpcClient
return client
}

View File

@@ -17,12 +17,23 @@ var (
ErrServer = errors.New("client error while processing request")
// ErrUnknownPayload corresponds to JSON-RPC code -32001.
ErrUnknownPayload = errors.New("payload does not exist or is not available")
// ErrUnknownPayloadStatus when the payload status is unknown.
ErrUnknownPayloadStatus = errors.New("unknown payload status")
// ErrUnsupportedScheme for unsupported URL schemes.
ErrUnsupportedScheme = errors.New("unsupported url scheme, only http(s) and ipc are supported")
// ErrConfigMismatch when the execution node's terminal total difficulty or
// terminal block hash received via the API mismatches Prysm's configuration value.
ErrConfigMismatch = errors.New("execution client configuration mismatch")
// ErrMismatchTerminalBlockHash when the terminal block hash value received via
// the API mismatches Prysm's configuration value.
ErrMismatchTerminalBlockHash = errors.New("terminal block hash mismatch")
// ErrMismatchTerminalTotalDiff when the terminal total difficulty value received via
// the API mismatches Prysm's configuration value.
ErrMismatchTerminalTotalDiff = errors.New("terminal total difficulty mismatch")
// ErrAcceptedSyncingPayloadStatus when the status of the payload is syncing or accepted.
ErrAcceptedSyncingPayloadStatus = errors.New("payload status is SYNCING or ACCEPTED")
// ErrInvalidPayloadStatus when the status of the payload is invalid.
ErrInvalidPayloadStatus = errors.New("payload status is INVALID")
// ErrNilResponse when the response is nil.
ErrNilResponse = errors.New("nil response")
)

View File

@@ -0,0 +1,12 @@
load("@prysm//tools/go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["client.go"],
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/powchain/engine-api-client/v1/mocks",
visibility = ["//visibility:public"],
deps = [
"//proto/engine/v1:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
],
)

View File

@@ -0,0 +1,50 @@
package mocks
import (
"context"
"github.com/ethereum/go-ethereum/common"
pb "github.com/prysmaticlabs/prysm/proto/engine/v1"
)
// EngineClient --
type EngineClient struct {
NewPayloadResp []byte
PayloadIDBytes *pb.PayloadIDBytes
ForkChoiceUpdatedResp []byte
ExecutionPayload *pb.ExecutionPayload
Err error
ExecutionBlock *pb.ExecutionBlock
}
// NewPayload --
func (e *EngineClient) NewPayload(_ context.Context, _ *pb.ExecutionPayload) ([]byte, error) {
return e.NewPayloadResp, nil
}
// ForkchoiceUpdated --
func (e *EngineClient) ForkchoiceUpdated(
_ context.Context, _ *pb.ForkchoiceState, _ *pb.PayloadAttributes,
) (*pb.PayloadIDBytes, []byte, error) {
return e.PayloadIDBytes, e.ForkChoiceUpdatedResp, nil
}
// GetPayload --
func (e *EngineClient) GetPayload(_ context.Context, _ [8]byte) (*pb.ExecutionPayload, error) {
return e.ExecutionPayload, nil
}
// ExchangeTransitionConfiguration --
func (e *EngineClient) ExchangeTransitionConfiguration(_ context.Context, _ *pb.TransitionConfiguration) error {
return e.Err
}
// LatestExecutionBlock --
func (e *EngineClient) LatestExecutionBlock(_ context.Context) (*pb.ExecutionBlock, error) {
return e.ExecutionBlock, nil
}
// ExecutionBlockByHash --
func (e *EngineClient) ExecutionBlockByHash(_ context.Context, _ common.Hash) (*pb.ExecutionBlock, error) {
return e.ExecutionBlock, nil
}

View File

@@ -19,11 +19,21 @@ func defaultConfig() *config {
}
}
// WithHTTPClient allows setting a custom HTTP client
// for the API connection.
func WithHTTPClient(httpClient *http.Client) Option {
// WithJWTSecret allows setting a JWT secret for authenticating
// the client via HTTP connections.
func WithJWTSecret(secret []byte) Option {
return func(c *Client) error {
c.cfg.httpClient = httpClient
if len(secret) == 0 {
return nil
}
authTransport := &jwtTransport{
underlyingTransport: http.DefaultTransport,
jwtSecret: secret,
}
c.cfg.httpClient = &http.Client{
Timeout: DefaultTimeout,
Transport: authTransport,
}
return nil
}
}

View File

@@ -40,6 +40,14 @@ func WithExecutionEndpoint(endpoint string) Option {
}
}
// WithExecutionClientJWTSecret for authenticating the execution node JSON-RPC endpoint.
func WithExecutionClientJWTSecret(jwtSecret []byte) Option {
return func(s *Service) error {
s.cfg.executionEndpointJWTSecret = jwtSecret
return nil
}
}
// WithDepositContractAddress for the deposit contract.
func WithDepositContractAddress(addr common.Address) Option {
return func(s *Service) error {

View File

@@ -127,17 +127,18 @@ type RPCClient interface {
// config defines a config struct for dependencies into the service.
type config struct {
depositContractAddr common.Address
beaconDB db.HeadAccessDatabase
depositCache *depositcache.DepositCache
stateNotifier statefeed.Notifier
stateGen *stategen.State
eth1HeaderReqLimit uint64
beaconNodeStatsUpdater BeaconNodeStatsUpdater
httpEndpoints []network.Endpoint
executionEndpoint string
currHttpEndpoint network.Endpoint
finalizedStateAtStartup state.BeaconState
depositContractAddr common.Address
beaconDB db.HeadAccessDatabase
depositCache *depositcache.DepositCache
stateNotifier statefeed.Notifier
stateGen *stategen.State
eth1HeaderReqLimit uint64
beaconNodeStatsUpdater BeaconNodeStatsUpdater
httpEndpoints []network.Endpoint
executionEndpoint string
executionEndpointJWTSecret []byte
currHttpEndpoint network.Endpoint
finalizedStateAtStartup state.BeaconState
}
// Service fetches important information about the canonical
@@ -156,7 +157,7 @@ type Service struct {
headTicker *time.Ticker
httpLogger bind.ContractFilterer
eth1DataFetcher RPCDataFetcher
engineAPIClient *engine.Client
engineAPIClient engine.Caller
rpcClient RPCClient
headerCache *headerCache // cache to store block hash/block height.
latestEth1Data *ethpb.LatestETH1Data
@@ -216,6 +217,9 @@ func NewService(ctx context.Context, opts ...Option) (*Service, error) {
return nil, errors.Wrap(err, "unable to initialize engine API client")
}
// Check transition configuration for the engine API client in the background.
go s.checkTransitionConfiguration(ctx)
if err := s.ensureValidPowchainData(ctx); err != nil {
return nil, errors.Wrap(err, "unable to validate powchain data")
}
@@ -298,15 +302,12 @@ func (s *Service) Status() error {
return nil
}
// get error from run function
if s.runError != nil {
return s.runError
}
return nil
return s.runError
}
// EngineAPIClient returns the associated engine API client to interact
// with an execution node via JSON-RPC.
func (s *Service) EngineAPIClient() *engine.Client {
func (s *Service) EngineAPIClient() engine.Caller {
return s.engineAPIClient
}
@@ -1058,7 +1059,10 @@ func (s *Service) initializeEngineAPIClient(ctx context.Context) error {
if s.cfg.executionEndpoint == "" {
return nil
}
client, err := engine.New(ctx, s.cfg.executionEndpoint)
opts := []engine.Option{
engine.WithJWTSecret(s.cfg.executionEndpointJWTSecret),
}
client, err := engine.New(ctx, s.cfg.executionEndpoint, opts...)
if err != nil {
return err
}

View File

@@ -74,7 +74,7 @@ func handleGetSSZ(
apimiddleware.WriteError(w, errJson, nil)
return true
}
grpcResponse, errJson := apimiddleware.ProxyRequest(req)
grpcResponse, errJson := m.ProxyRequest(req)
if errJson != nil {
apimiddleware.WriteError(w, errJson, nil)
return true

View File

@@ -39,7 +39,7 @@ func (vs *Server) getBellatrixBeaconBlock(ctx context.Context, req *ethpb.BlockR
StateRoot: make([]byte, fieldparams.RootLength),
ReceiptsRoot: make([]byte, fieldparams.RootLength),
LogsBloom: make([]byte, fieldparams.LogsBloomLength),
Random: make([]byte, fieldparams.RootLength),
PrevRandao: make([]byte, fieldparams.RootLength),
BaseFeePerGas: make([]byte, fieldparams.RootLength),
BlockHash: make([]byte, fieldparams.RootLength),
}, // TODO(9853) Insert real execution payload.

View File

@@ -2268,7 +2268,7 @@ func TestProposer_GetBeaconBlock_BellatrixEpoch(t *testing.T) {
StateRoot: make([]byte, fieldparams.RootLength),
ReceiptsRoot: make([]byte, fieldparams.RootLength),
LogsBloom: make([]byte, fieldparams.LogsBloomLength),
Random: make([]byte, fieldparams.RootLength),
PrevRandao: make([]byte, fieldparams.RootLength),
BaseFeePerGas: make([]byte, fieldparams.RootLength),
BlockHash: make([]byte, fieldparams.RootLength),
},

View File

@@ -20,7 +20,7 @@ func TestFieldTrie_NewTrie(t *testing.T) {
// 5 represents the enum value of state roots
trie, err := fieldtrie.NewFieldTrie(5, stateTypes.BasicArray, newState.StateRoots(), uint64(params.BeaconConfig().SlotsPerHistoricalRoot))
require.NoError(t, err)
root, err := stateutil.RootsArrayHashTreeRoot(newState.StateRoots(), uint64(params.BeaconConfig().SlotsPerHistoricalRoot), "StateRoots")
root, err := stateutil.RootsArrayHashTreeRoot(newState.StateRoots(), uint64(params.BeaconConfig().SlotsPerHistoricalRoot))
require.NoError(t, err)
newRoot, err := trie.TrieRoot()
require.NoError(t, err)

View File

@@ -4,15 +4,11 @@ import (
"context"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
"github.com/prysmaticlabs/prysm/config/features"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
// computeFieldRoots returns the hash tree root computations of every field in
// the beacon state as a list of 32 byte roots.
func computeFieldRoots(ctx context.Context, state *ethpb.BeaconState) ([][]byte, error) {
if features.Get().EnableSSZCache {
return stateutil.CachedHasher.ComputeFieldRootsWithHasherPhase0(ctx, state)
}
return stateutil.NocachedHasher.ComputeFieldRootsWithHasherPhase0(ctx, state)
return stateutil.ComputeFieldRootsWithHasherPhase0(ctx, state)
}

View File

@@ -258,3 +258,21 @@ func TestBeaconState_AppendValidator_DoesntMutateCopy(t *testing.T) {
_, ok := st1.ValidatorIndexByPubkey(bytesutil.ToBytes48(val.PublicKey))
assert.Equal(t, false, ok, "Expected no validator index to be present in st1 for the newly inserted pubkey")
}
func BenchmarkBeaconState(b *testing.B) {
testState, _ := util.DeterministicGenesisState(b, 16000)
pbState, err := v1.ProtobufBeaconState(testState.InnerStateUnsafe())
require.NoError(b, err)
b.Run("Vectorized SHA256", func(b *testing.B) {
st, err := v1.InitializeFromProtoUnsafe(pbState)
require.NoError(b, err)
_, err = st.HashTreeRoot(context.Background())
assert.NoError(b, err)
})
b.Run("Current SHA256", func(b *testing.B) {
_, err := pbState.HashTreeRoot()
require.NoError(b, err)
})
}

View File

@@ -4,15 +4,11 @@ import (
"context"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
"github.com/prysmaticlabs/prysm/config/features"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
// computeFieldRoots returns the hash tree root computations of every field in
// the beacon state as a list of 32 byte roots.
func computeFieldRoots(ctx context.Context, state *ethpb.BeaconStateAltair) ([][]byte, error) {
if features.Get().EnableSSZCache {
return stateutil.CachedHasher.ComputeFieldRootsWithHasherAltair(ctx, state)
}
return stateutil.NocachedHasher.ComputeFieldRootsWithHasherAltair(ctx, state)
return stateutil.ComputeFieldRootsWithHasherAltair(ctx, state)
}

View File

@@ -4,15 +4,11 @@ import (
"context"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
"github.com/prysmaticlabs/prysm/config/features"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
// computeFieldRoots returns the hash tree root computations of every field in
// the beacon state as a list of 32 byte roots.
func computeFieldRoots(ctx context.Context, state *ethpb.BeaconStateBellatrix) ([][]byte, error) {
if features.Get().EnableSSZCache {
return stateutil.CachedHasher.ComputeFieldRootsWithHasherBellatrix(ctx, state)
}
return stateutil.NocachedHasher.ComputeFieldRootsWithHasherBellatrix(ctx, state)
return stateutil.ComputeFieldRootsWithHasherBellatrix(ctx, state)
}

View File

@@ -61,7 +61,7 @@ func TestBeaconState_AppendBalanceWithTrie(t *testing.T) {
StateRoot: make([]byte, fieldparams.RootLength),
ReceiptRoot: make([]byte, fieldparams.RootLength),
LogsBloom: make([]byte, 256),
Random: make([]byte, fieldparams.RootLength),
PrevRandao: make([]byte, fieldparams.RootLength),
BaseFeePerGas: make([]byte, fieldparams.RootLength),
BlockHash: make([]byte, fieldparams.RootLength),
TransactionsRoot: make([]byte, fieldparams.RootLength),

View File

@@ -37,11 +37,11 @@ go_library(
"//config/params:go_default_library",
"//container/trie:go_default_library",
"//crypto/hash:go_default_library",
"//crypto/hash/htr:go_default_library",
"//encoding/bytesutil:go_default_library",
"//encoding/ssz:go_default_library",
"//math:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"@com_github_dgraph_io_ristretto//:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_prysmaticlabs_eth2_types//:go_default_library",
"@io_opencensus_go//trace:go_default_library",
@@ -53,20 +53,22 @@ go_test(
srcs = [
"benchmark_test.go",
"field_root_test.go",
"field_root_validator_test.go",
"reference_bench_test.go",
"state_root_test.go",
"stateutil_test.go",
"trie_helpers_test.go",
"validator_root_test.go",
],
embed = [":go_default_library"],
deps = [
"//beacon-chain/state:go_default_library",
"//config/features:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//crypto/hash:go_default_library",
"//encoding/bytesutil:go_default_library",
"//encoding/ssz:go_default_library",
"//math:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//runtime/interop:go_default_library",
"//testing/assert:go_default_library",

View File

@@ -12,27 +12,6 @@ import (
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
// eth1DataEncKey returns the encoded key in bytes of input `eth1Data`,
// the returned key bytes can be used for caching purposes.
func eth1DataEncKey(eth1Data *ethpb.Eth1Data) []byte {
enc := make([]byte, 0, 96)
if eth1Data != nil {
if len(eth1Data.DepositRoot) > 0 {
depRoot := bytesutil.ToBytes32(eth1Data.DepositRoot)
enc = append(enc, depRoot[:]...)
}
eth1DataCountBuf := make([]byte, 8)
binary.LittleEndian.PutUint64(eth1DataCountBuf, eth1Data.DepositCount)
eth1CountRoot := bytesutil.ToBytes32(eth1DataCountBuf)
enc = append(enc, eth1CountRoot[:]...)
if len(eth1Data.BlockHash) > 0 {
blockHash := bytesutil.ToBytes32(eth1Data.BlockHash)
enc = append(enc, blockHash[:]...)
}
}
return enc
}
// Eth1DataRootWithHasher returns the hash tree root of input `eth1Data`.
func Eth1DataRootWithHasher(hasher ssz.HashFn, eth1Data *ethpb.Eth1Data) ([32]byte, error) {
if eth1Data == nil {
@@ -62,22 +41,6 @@ func Eth1DataRootWithHasher(hasher ssz.HashFn, eth1Data *ethpb.Eth1Data) ([32]by
return root, nil
}
// Eth1DatasEncKey returns the encoded key in bytes of input `eth1Data`s,
// the returned key bytes can be used for caching purposes.
func Eth1DatasEncKey(eth1Datas []*ethpb.Eth1Data) ([32]byte, error) {
hasher := hash.CustomSHA256Hasher()
enc := make([]byte, len(eth1Datas)*32)
for i := 0; i < len(eth1Datas); i++ {
eth1, err := Eth1DataRootWithHasher(hasher, eth1Datas[i])
if err != nil {
return [32]byte{}, errors.Wrap(err, "could not compute eth1data merkleization")
}
copy(enc[(i*32):(i+1)*32], eth1[:])
}
hashKey := hash.FastSum256(enc)
return hashKey, nil
}
// Eth1DatasRoot returns the hash tree root of input `eth1Datas`.
func Eth1DatasRoot(eth1Datas []*ethpb.Eth1Data) ([32]byte, error) {
hasher := hash.CustomSHA256Hasher()

View File

@@ -6,7 +6,6 @@ import (
"fmt"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/config/features"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
"github.com/prysmaticlabs/prysm/crypto/hash"
"github.com/prysmaticlabs/prysm/encoding/ssz"
@@ -15,14 +14,11 @@ import (
// RootsArrayHashTreeRoot computes the Merkle root of arrays of 32-byte hashes, such as [64][32]byte
// according to the Simple Serialize specification of Ethereum.
func RootsArrayHashTreeRoot(vals [][]byte, length uint64, fieldName string) ([32]byte, error) {
if features.Get().EnableSSZCache {
return CachedHasher.arraysRoot(vals, length, fieldName)
}
return NocachedHasher.arraysRoot(vals, length, fieldName)
func RootsArrayHashTreeRoot(vals [][]byte, length uint64) ([32]byte, error) {
return arraysRoot(vals, length)
}
func (h *stateRootHasher) epochAttestationsRoot(atts []*ethpb.PendingAttestation) ([32]byte, error) {
func epochAttestationsRoot(atts []*ethpb.PendingAttestation) ([32]byte, error) {
max := uint64(fieldparams.CurrentEpochAttestationsLength)
if uint64(len(atts)) > max {
return [32]byte{}, fmt.Errorf("epoch attestation exceeds max length %d", max)
@@ -31,7 +27,7 @@ func (h *stateRootHasher) epochAttestationsRoot(atts []*ethpb.PendingAttestation
hasher := hash.CustomSHA256Hasher()
roots := make([][]byte, len(atts))
for i := 0; i < len(atts); i++ {
pendingRoot, err := h.pendingAttestationRoot(hasher, atts[i])
pendingRoot, err := pendingAttestationRoot(hasher, atts[i])
if err != nil {
return [32]byte{}, errors.Wrap(err, "could not attestation merkleization")
}
@@ -58,26 +54,9 @@ func (h *stateRootHasher) epochAttestationsRoot(atts []*ethpb.PendingAttestation
return res, nil
}
func (h *stateRootHasher) pendingAttestationRoot(hasher ssz.HashFn, att *ethpb.PendingAttestation) ([32]byte, error) {
func pendingAttestationRoot(hasher ssz.HashFn, att *ethpb.PendingAttestation) ([32]byte, error) {
if att == nil {
return [32]byte{}, errors.New("nil pending attestation")
}
// Marshal attestation to determine if it exists in the cache.
enc := pendingAttEncKey(att)
// Check if it exists in cache:
if h.rootsCache != nil {
if found, ok := h.rootsCache.Get(string(enc)); found != nil && ok {
return found.([32]byte), nil
}
}
res, err := PendingAttRootWithHasher(hasher, att)
if err != nil {
return [32]byte{}, err
}
if h.rootsCache != nil {
h.rootsCache.Set(string(enc), res, 32)
}
return res, nil
return PendingAttRootWithHasher(hasher, att)
}

View File

@@ -2,7 +2,6 @@ package stateutil
import (
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/config/features"
"github.com/prysmaticlabs/prysm/encoding/ssz"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
@@ -14,45 +13,12 @@ func Eth1Root(hasher ssz.HashFn, eth1Data *ethpb.Eth1Data) ([32]byte, error) {
if eth1Data == nil {
return [32]byte{}, errors.New("nil eth1 data")
}
enc := eth1DataEncKey(eth1Data)
if features.Get().EnableSSZCache {
if found, ok := CachedHasher.rootsCache.Get(string(enc)); ok && found != nil {
return found.([32]byte), nil
}
}
root, err := Eth1DataRootWithHasher(hasher, eth1Data)
if err != nil {
return [32]byte{}, err
}
if features.Get().EnableSSZCache {
CachedHasher.rootsCache.Set(string(enc), root, 32)
}
return root, nil
return Eth1DataRootWithHasher(hasher, eth1Data)
}
// eth1DataVotesRoot computes the HashTreeRoot Merkleization of
// a list of Eth1Data structs according to the eth2
// Simple Serialize specification.
func eth1DataVotesRoot(eth1DataVotes []*ethpb.Eth1Data) ([32]byte, error) {
hashKey, err := Eth1DatasEncKey(eth1DataVotes)
if err != nil {
return [32]byte{}, err
}
if features.Get().EnableSSZCache {
if found, ok := CachedHasher.rootsCache.Get(string(hashKey[:])); ok && found != nil {
return found.([32]byte), nil
}
}
root, err := Eth1DatasRoot(eth1DataVotes)
if err != nil {
return [32]byte{}, err
}
if features.Get().EnableSSZCache {
CachedHasher.rootsCache.Set(string(hashKey[:]), root, 32)
}
return root, nil
return Eth1DatasRoot(eth1DataVotes)
}

View File

@@ -7,17 +7,17 @@ import (
)
func TestArraysTreeRoot_OnlyPowerOf2(t *testing.T) {
_, err := NocachedHasher.arraysRoot([][]byte{}, 1, "testing")
_, err := arraysRoot([][]byte{}, 1)
assert.NoError(t, err)
_, err = NocachedHasher.arraysRoot([][]byte{}, 4, "testing")
_, err = arraysRoot([][]byte{}, 4)
assert.NoError(t, err)
_, err = NocachedHasher.arraysRoot([][]byte{}, 8, "testing")
_, err = arraysRoot([][]byte{}, 8)
assert.NoError(t, err)
_, err = NocachedHasher.arraysRoot([][]byte{}, 10, "testing")
_, err = arraysRoot([][]byte{}, 10)
assert.ErrorContains(t, "hash layer is a non power of 2", err)
}
func TestArraysTreeRoot_ZeroLength(t *testing.T) {
_, err := NocachedHasher.arraysRoot([][]byte{}, 0, "testing")
_, err := arraysRoot([][]byte{}, 0)
assert.ErrorContains(t, "zero leaves provided", err)
}

View File

@@ -8,40 +8,43 @@ import (
"github.com/prysmaticlabs/prysm/config/features"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
"github.com/prysmaticlabs/prysm/crypto/hash"
"github.com/prysmaticlabs/prysm/crypto/hash/htr"
"github.com/prysmaticlabs/prysm/encoding/ssz"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
const (
// number of field roots for the validator object.
validatorFieldRoots = 8
// Depth of tree representation of an individual
// validator.
// NumOfRoots = 2 ^ (TreeDepth)
// 8 = 2 ^ 3
validatorTreeDepth = 3
)
// ValidatorRegistryRoot computes the HashTreeRoot Merkleization of
// a list of validator structs according to the Ethereum
// Simple Serialize specification.
func ValidatorRegistryRoot(vals []*ethpb.Validator) ([32]byte, error) {
if features.Get().EnableSSZCache {
return CachedHasher.validatorRegistryRoot(vals)
}
return NocachedHasher.validatorRegistryRoot(vals)
return validatorRegistryRoot(vals)
}
func (h *stateRootHasher) validatorRegistryRoot(validators []*ethpb.Validator) ([32]byte, error) {
hashKeyElements := make([]byte, len(validators)*32)
roots := make([][32]byte, len(validators))
emptyKey := hash.FastSum256(hashKeyElements)
func validatorRegistryRoot(validators []*ethpb.Validator) ([32]byte, error) {
hasher := hash.CustomSHA256Hasher()
bytesProcessed := 0
for i := 0; i < len(validators); i++ {
val, err := h.validatorRoot(hasher, validators[i])
if err != nil {
return [32]byte{}, errors.Wrap(err, "could not compute validators merkleization")
}
copy(hashKeyElements[bytesProcessed:bytesProcessed+32], val[:])
roots[i] = val
bytesProcessed += 32
}
hashKey := hash.FastSum256(hashKeyElements)
if hashKey != emptyKey && h.rootsCache != nil {
if found, ok := h.rootsCache.Get(string(hashKey[:])); found != nil && ok {
return found.([32]byte), nil
var err error
var roots [][32]byte
if features.Get().EnableVectorizedHTR {
roots, err = optimizedValidatorRoots(validators)
if err != nil {
return [32]byte{}, err
}
} else {
roots, err = validatorRoots(hasher, validators)
if err != nil {
return [32]byte{}, err
}
}
@@ -57,32 +60,49 @@ func (h *stateRootHasher) validatorRegistryRoot(validators []*ethpb.Validator) (
var validatorsRootsBufRoot [32]byte
copy(validatorsRootsBufRoot[:], validatorsRootsBuf.Bytes())
res := ssz.MixInLength(validatorsRootsRoot, validatorsRootsBufRoot[:])
if hashKey != emptyKey && h.rootsCache != nil {
h.rootsCache.Set(string(hashKey[:]), res, 32)
}
return res, nil
}
func (h *stateRootHasher) validatorRoot(hasher ssz.HashFn, validator *ethpb.Validator) ([32]byte, error) {
func validatorRoots(hasher func([]byte) [32]byte, validators []*ethpb.Validator) ([][32]byte, error) {
roots := make([][32]byte, len(validators))
for i := 0; i < len(validators); i++ {
val, err := validatorRoot(hasher, validators[i])
if err != nil {
return [][32]byte{}, errors.Wrap(err, "could not compute validators merkleization")
}
roots[i] = val
}
return roots, nil
}
func optimizedValidatorRoots(validators []*ethpb.Validator) ([][32]byte, error) {
roots := make([][32]byte, 0, len(validators)*validatorFieldRoots)
hasher := hash.CustomSHA256Hasher()
for i := 0; i < len(validators); i++ {
fRoots, err := ValidatorFieldRoots(hasher, validators[i])
if err != nil {
return [][32]byte{}, errors.Wrap(err, "could not compute validators merkleization")
}
roots = append(roots, fRoots...)
}
// A validator's tree can represented with a depth of 3. As log2(8) = 3
// Using this property we can lay out all the individual fields of a
// validator and hash them in single level using our vectorized routine.
for i := 0; i < validatorTreeDepth; i++ {
// Overwrite input lists as we are hashing by level
// and only need the highest level to proceed.
outputLen := len(roots) / 2
htr.VectorizedSha256(roots, roots)
roots = roots[:outputLen]
}
return roots, nil
}
func validatorRoot(hasher ssz.HashFn, validator *ethpb.Validator) ([32]byte, error) {
if validator == nil {
return [32]byte{}, errors.New("nil validator")
}
enc := validatorEncKey(validator)
// Check if it exists in cache:
if h.rootsCache != nil {
if found, ok := h.rootsCache.Get(string(enc)); found != nil && ok {
return found.([32]byte), nil
}
}
valRoot, err := ValidatorRootWithHasher(hasher, validator)
if err != nil {
return [32]byte{}, err
}
if h.rootsCache != nil {
h.rootsCache.Set(string(enc), valRoot, 32)
}
return valRoot, nil
return ValidatorRootWithHasher(hasher, validator)
}

View File

@@ -0,0 +1,32 @@
package stateutil
import (
"reflect"
"strings"
"testing"
mathutil "github.com/prysmaticlabs/prysm/math"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/testing/assert"
)
func TestValidatorConstants(t *testing.T) {
v := &ethpb.Validator{}
refV := reflect.ValueOf(v).Elem()
numFields := refV.NumField()
numOfValFields := 0
for i := 0; i < numFields; i++ {
if strings.Contains(refV.Type().Field(i).Name, "state") ||
strings.Contains(refV.Type().Field(i).Name, "sizeCache") ||
strings.Contains(refV.Type().Field(i).Name, "unknownFields") {
continue
}
numOfValFields++
}
assert.Equal(t, validatorFieldRoots, numOfValFields)
assert.Equal(t, uint64(validatorFieldRoots), mathutil.PowerOf2(validatorTreeDepth))
_, err := ValidatorRegistryRoot([]*ethpb.Validator{v})
assert.NoError(t, err)
}

View File

@@ -6,129 +6,23 @@ import (
"github.com/prysmaticlabs/prysm/encoding/ssz"
)
func (h *stateRootHasher) arraysRoot(input [][]byte, length uint64, fieldName string) ([32]byte, error) {
lock.Lock()
defer lock.Unlock()
func arraysRoot(input [][]byte, length uint64) ([32]byte, error) {
hashFunc := hash.CustomSHA256Hasher()
if _, ok := layersCache[fieldName]; !ok && h.rootsCache != nil {
depth := ssz.Depth(length)
layersCache[fieldName] = make([][][32]byte, depth+1)
}
leaves := make([][32]byte, length)
for i, chunk := range input {
copy(leaves[i][:], chunk)
}
bytesProcessed := 0
changedIndices := make([]int, 0)
prevLeaves, ok := leavesCache[fieldName]
if len(prevLeaves) == 0 || h.rootsCache == nil {
prevLeaves = leaves
}
// Exit early if our previous leaves length don't match with the current set.
// This should never happen but better to be defensive here.
if len(prevLeaves) != len(leaves) {
res, err := h.merkleizeWithCache(leaves, length, fieldName, hashFunc)
if err != nil {
return [32]byte{}, err
}
if h.rootsCache != nil {
leavesCache[fieldName] = leaves
}
return res, nil
}
for i := 0; i < len(leaves); i++ {
// We check if any items changed since the roots were last recomputed.
notEqual := leaves[i] != prevLeaves[i]
if ok && h.rootsCache != nil && notEqual {
changedIndices = append(changedIndices, i)
}
bytesProcessed += 32
}
if len(changedIndices) > 0 && h.rootsCache != nil {
var rt [32]byte
var err error
// If indices did change since last computation, we only recompute
// the modified branches in the cached Merkle tree for this state field.
chunks := leaves
// We need to ensure we recompute indices of the Merkle tree which
// changed in-between calls to this function. This check adds an offset
// to the recomputed indices to ensure we do so evenly.
maxChangedIndex := changedIndices[len(changedIndices)-1]
if maxChangedIndex+2 == len(chunks) && maxChangedIndex%2 != 0 {
changedIndices = append(changedIndices, maxChangedIndex+1)
}
for i := 0; i < len(changedIndices); i++ {
rt, err = recomputeRoot(changedIndices[i], chunks, fieldName, hashFunc)
if err != nil {
return [32]byte{}, err
}
}
leavesCache[fieldName] = chunks
return rt, nil
}
res, err := h.merkleizeWithCache(leaves, length, fieldName, hashFunc)
res, err := merkleize(leaves, length, hashFunc)
if err != nil {
return [32]byte{}, err
}
if h.rootsCache != nil {
leavesCache[fieldName] = leaves
}
return res, nil
}
func recomputeRoot(idx int, chunks [][32]byte, fieldName string, hasher func([]byte) [32]byte) ([32]byte, error) {
items, ok := layersCache[fieldName]
if !ok {
return [32]byte{}, errors.New("could not recompute root as there was no cache found")
}
if items == nil {
return [32]byte{}, errors.New("could not recompute root as there were no items found in the layers cache")
}
layers := items
root := chunks[idx]
layers[0] = chunks
// The merkle tree structure looks as follows:
// [[r1, r2, r3, r4], [parent1, parent2], [root]]
// Using information about the index which changed, idx, we recompute
// only its branch up the tree.
currentIndex := idx
for i := 0; i < len(layers)-1; i++ {
isLeft := currentIndex%2 == 0
neighborIdx := currentIndex ^ 1
neighbor := [32]byte{}
if layers[i] != nil && len(layers[i]) != 0 && neighborIdx < len(layers[i]) {
neighbor = layers[i][neighborIdx]
}
if isLeft {
parentHash := hasher(append(root[:], neighbor[:]...))
root = parentHash
} else {
parentHash := hasher(append(neighbor[:], root[:]...))
root = parentHash
}
parentIdx := currentIndex / 2
// Update the cached layers at the parent index.
if len(layers[i+1]) == 0 {
layers[i+1] = append(layers[i+1], root)
} else {
layers[i+1][parentIdx] = root
}
currentIndex = parentIdx
}
layersCache[fieldName] = layers
// If there is only a single leaf, we return it (the identity element).
if len(layers[0]) == 1 {
return layers[0][0], nil
}
return root, nil
}
func (h *stateRootHasher) merkleizeWithCache(leaves [][32]byte, length uint64,
fieldName string, hasher func([]byte) [32]byte) ([32]byte, error) {
func merkleize(leaves [][32]byte, length uint64,
hasher func([]byte) [32]byte) ([32]byte, error) {
if len(leaves) == 0 {
return [32]byte{}, errors.New("zero leaves provided")
}
@@ -137,20 +31,12 @@ func (h *stateRootHasher) merkleizeWithCache(leaves [][32]byte, length uint64,
}
hashLayer := leaves
layers := make([][][32]byte, ssz.Depth(length)+1)
if items, ok := layersCache[fieldName]; ok && h.rootsCache != nil {
if len(items[0]) == len(leaves) {
layers = items
}
}
layers[0] = hashLayer
var err error
layers, hashLayer, err = MerkleizeTrieLeaves(layers, hashLayer, hasher)
_, hashLayer, err = MerkleizeTrieLeaves(layers, hashLayer, hasher)
if err != nil {
return [32]byte{}, err
}
root := hashLayer[0]
if h.rootsCache != nil {
layersCache[fieldName] = layers
}
return root, nil
}

View File

@@ -40,29 +40,6 @@ func PendingAttRootWithHasher(hasher ssz.HashFn, att *ethpb.PendingAttestation)
return ssz.BitwiseMerkleizeArrays(hasher, fieldRoots, uint64(len(fieldRoots)), uint64(len(fieldRoots)))
}
// pendingAttEncKey returns the encoded key in bytes of input `pendingAttestation`,
// the returned key bytes can be used for caching purposes.
func pendingAttEncKey(att *ethpb.PendingAttestation) []byte {
enc := make([]byte, 2192)
if att != nil {
copy(enc[0:2048], att.AggregationBits)
inclusionBuf := make([]byte, 8)
binary.LittleEndian.PutUint64(inclusionBuf, uint64(att.InclusionDelay))
copy(enc[2048:2056], inclusionBuf)
attDataBuf := marshalAttData(att.Data)
copy(enc[2056:2184], attDataBuf)
proposerBuf := make([]byte, 8)
binary.LittleEndian.PutUint64(proposerBuf, uint64(att.ProposerIndex))
copy(enc[2184:2192], proposerBuf)
}
return enc
}
func attDataRootWithHasher(hasher ssz.HashFn, data *ethpb.AttestationData) ([32]byte, error) {
fieldRoots := make([][]byte, 5)
@@ -100,39 +77,3 @@ func attDataRootWithHasher(hasher ssz.HashFn, data *ethpb.AttestationData) ([32]
return ssz.BitwiseMerkleize(hasher, fieldRoots, uint64(len(fieldRoots)), uint64(len(fieldRoots)))
}
func marshalAttData(data *ethpb.AttestationData) []byte {
enc := make([]byte, 128)
if data != nil {
// Slot.
slotBuf := make([]byte, 8)
binary.LittleEndian.PutUint64(slotBuf, uint64(data.Slot))
copy(enc[0:8], slotBuf)
// Committee index.
indexBuf := make([]byte, 8)
binary.LittleEndian.PutUint64(indexBuf, uint64(data.CommitteeIndex))
copy(enc[8:16], indexBuf)
copy(enc[16:48], data.BeaconBlockRoot)
// Source epoch and root.
if data.Source != nil {
sourceEpochBuf := make([]byte, 8)
binary.LittleEndian.PutUint64(sourceEpochBuf, uint64(data.Source.Epoch))
copy(enc[48:56], sourceEpochBuf)
copy(enc[56:88], data.Source.Root)
}
// Target.
if data.Target != nil {
targetEpochBuf := make([]byte, 8)
binary.LittleEndian.PutUint64(targetEpochBuf, uint64(data.Target.Epoch))
copy(enc[88:96], targetEpochBuf)
copy(enc[96:128], data.Target.Root)
}
}
return enc
}

View File

@@ -3,9 +3,7 @@ package stateutil
import (
"context"
"encoding/binary"
"sync"
"github.com/dgraph-io/ristretto"
"github.com/pkg/errors"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
"github.com/prysmaticlabs/prysm/config/params"
@@ -16,45 +14,9 @@ import (
"go.opencensus.io/trace"
)
var (
// Set the map size as equal to that of the latest state field count.
leavesCache = make(map[string][][32]byte, params.BeaconConfig().BeaconStateBellatrixFieldCount)
layersCache = make(map[string][][][32]byte, params.BeaconConfig().BeaconStateBellatrixFieldCount)
lock sync.RWMutex
)
const cacheSize = 100000
// NocachedHasher references a hasher that will not utilize a cache.
var NocachedHasher *stateRootHasher
// CachedHasher references a hasher that will utilize a roots cache.
var CachedHasher *stateRootHasher
func init() {
rootsCache, err := ristretto.NewCache(&ristretto.Config{
NumCounters: cacheSize, // number of keys to track frequency of (1M).
MaxCost: 1 << 22, // maximum cost of cache (3MB).
// 100,000 roots will take up approximately 3 MB in memory.
BufferItems: 64, // number of keys per Get buffer.
})
if err != nil {
panic(err)
}
// Temporarily disable roots cache until cache issues can be resolved.
CachedHasher = &stateRootHasher{rootsCache: rootsCache}
NocachedHasher = &stateRootHasher{}
}
// stateRootHasher defines an object through which we can
// hash the different fields in the state with a few cached layers.
type stateRootHasher struct {
rootsCache *ristretto.Cache
}
// ComputeFieldRootsWithHasherPhase0 hashes the provided phase 0 state and returns its respective field roots.
func (h *stateRootHasher) ComputeFieldRootsWithHasherPhase0(ctx context.Context, state *ethpb.BeaconState) ([][]byte, error) {
_, span := trace.StartSpan(ctx, "hasher.ComputeFieldRootsWithHasherPhase0")
func ComputeFieldRootsWithHasherPhase0(ctx context.Context, state *ethpb.BeaconState) ([][]byte, error) {
_, span := trace.StartSpan(ctx, "ComputeFieldRootsWithHasherPhase0")
defer span.End()
if state == nil {
@@ -91,14 +53,14 @@ func (h *stateRootHasher) ComputeFieldRootsWithHasherPhase0(ctx context.Context,
fieldRoots[4] = headerHashTreeRoot[:]
// BlockRoots array root.
blockRootsRoot, err := h.arraysRoot(state.BlockRoots, fieldparams.BlockRootsLength, "BlockRoots")
blockRootsRoot, err := arraysRoot(state.BlockRoots, fieldparams.BlockRootsLength)
if err != nil {
return nil, errors.Wrap(err, "could not compute block roots merkleization")
}
fieldRoots[5] = blockRootsRoot[:]
// StateRoots array root.
stateRootsRoot, err := h.arraysRoot(state.StateRoots, fieldparams.StateRootsLength, "StateRoots")
stateRootsRoot, err := arraysRoot(state.StateRoots, fieldparams.StateRootsLength)
if err != nil {
return nil, errors.Wrap(err, "could not compute state roots merkleization")
}
@@ -132,7 +94,7 @@ func (h *stateRootHasher) ComputeFieldRootsWithHasherPhase0(ctx context.Context,
fieldRoots[10] = eth1DepositBuf[:]
// Validators slice root.
validatorsRoot, err := h.validatorRegistryRoot(state.Validators)
validatorsRoot, err := validatorRegistryRoot(state.Validators)
if err != nil {
return nil, errors.Wrap(err, "could not compute validator registry merkleization")
}
@@ -146,7 +108,7 @@ func (h *stateRootHasher) ComputeFieldRootsWithHasherPhase0(ctx context.Context,
fieldRoots[12] = balancesRoot[:]
// RandaoMixes array root.
randaoRootsRoot, err := h.arraysRoot(state.RandaoMixes, fieldparams.RandaoMixesLength, "RandaoMixes")
randaoRootsRoot, err := arraysRoot(state.RandaoMixes, fieldparams.RandaoMixesLength)
if err != nil {
return nil, errors.Wrap(err, "could not compute randao roots merkleization")
}
@@ -160,14 +122,14 @@ func (h *stateRootHasher) ComputeFieldRootsWithHasherPhase0(ctx context.Context,
fieldRoots[14] = slashingsRootsRoot[:]
// PreviousEpochAttestations slice root.
prevAttsRoot, err := h.epochAttestationsRoot(state.PreviousEpochAttestations)
prevAttsRoot, err := epochAttestationsRoot(state.PreviousEpochAttestations)
if err != nil {
return nil, errors.Wrap(err, "could not compute previous epoch attestations merkleization")
}
fieldRoots[15] = prevAttsRoot[:]
// CurrentEpochAttestations slice root.
currAttsRoot, err := h.epochAttestationsRoot(state.CurrentEpochAttestations)
currAttsRoot, err := epochAttestationsRoot(state.CurrentEpochAttestations)
if err != nil {
return nil, errors.Wrap(err, "could not compute current epoch attestations merkleization")
}
@@ -201,8 +163,8 @@ func (h *stateRootHasher) ComputeFieldRootsWithHasherPhase0(ctx context.Context,
}
// ComputeFieldRootsWithHasherAltair hashes the provided altair state and returns its respective field roots.
func (h *stateRootHasher) ComputeFieldRootsWithHasherAltair(ctx context.Context, state *ethpb.BeaconStateAltair) ([][]byte, error) {
_, span := trace.StartSpan(ctx, "hasher.ComputeFieldRootsWithHasherAltair")
func ComputeFieldRootsWithHasherAltair(ctx context.Context, state *ethpb.BeaconStateAltair) ([][]byte, error) {
_, span := trace.StartSpan(ctx, "ComputeFieldRootsWithHasherAltair")
defer span.End()
if state == nil {
@@ -239,14 +201,14 @@ func (h *stateRootHasher) ComputeFieldRootsWithHasherAltair(ctx context.Context,
fieldRoots[4] = headerHashTreeRoot[:]
// BlockRoots array root.
blockRootsRoot, err := h.arraysRoot(state.BlockRoots, fieldparams.BlockRootsLength, "BlockRoots")
blockRootsRoot, err := arraysRoot(state.BlockRoots, fieldparams.BlockRootsLength)
if err != nil {
return nil, errors.Wrap(err, "could not compute block roots merkleization")
}
fieldRoots[5] = blockRootsRoot[:]
// StateRoots array root.
stateRootsRoot, err := h.arraysRoot(state.StateRoots, fieldparams.StateRootsLength, "StateRoots")
stateRootsRoot, err := arraysRoot(state.StateRoots, fieldparams.StateRootsLength)
if err != nil {
return nil, errors.Wrap(err, "could not compute state roots merkleization")
}
@@ -280,7 +242,7 @@ func (h *stateRootHasher) ComputeFieldRootsWithHasherAltair(ctx context.Context,
fieldRoots[10] = eth1DepositBuf[:]
// Validators slice root.
validatorsRoot, err := h.validatorRegistryRoot(state.Validators)
validatorsRoot, err := validatorRegistryRoot(state.Validators)
if err != nil {
return nil, errors.Wrap(err, "could not compute validator registry merkleization")
}
@@ -294,7 +256,7 @@ func (h *stateRootHasher) ComputeFieldRootsWithHasherAltair(ctx context.Context,
fieldRoots[12] = balancesRoot[:]
// RandaoMixes array root.
randaoRootsRoot, err := h.arraysRoot(state.RandaoMixes, fieldparams.RandaoMixesLength, "RandaoMixes")
randaoRootsRoot, err := arraysRoot(state.RandaoMixes, fieldparams.RandaoMixesLength)
if err != nil {
return nil, errors.Wrap(err, "could not compute randao roots merkleization")
}
@@ -371,8 +333,8 @@ func (h *stateRootHasher) ComputeFieldRootsWithHasherAltair(ctx context.Context,
}
// ComputeFieldRootsWithHasherBellatrix hashes the provided bellatrix state and returns its respective field roots.
func (h *stateRootHasher) ComputeFieldRootsWithHasherBellatrix(ctx context.Context, state *ethpb.BeaconStateBellatrix) ([][]byte, error) {
_, span := trace.StartSpan(ctx, "hasher.ComputeFieldRootsWithHasherBellatrix")
func ComputeFieldRootsWithHasherBellatrix(ctx context.Context, state *ethpb.BeaconStateBellatrix) ([][]byte, error) {
_, span := trace.StartSpan(ctx, "ComputeFieldRootsWithHasherBellatrix")
defer span.End()
if state == nil {
@@ -409,14 +371,14 @@ func (h *stateRootHasher) ComputeFieldRootsWithHasherBellatrix(ctx context.Conte
fieldRoots[4] = headerHashTreeRoot[:]
// BlockRoots array root.
blockRootsRoot, err := h.arraysRoot(state.BlockRoots, fieldparams.BlockRootsLength, "BlockRoots")
blockRootsRoot, err := arraysRoot(state.BlockRoots, fieldparams.BlockRootsLength)
if err != nil {
return nil, errors.Wrap(err, "could not compute block roots merkleization")
}
fieldRoots[5] = blockRootsRoot[:]
// StateRoots array root.
stateRootsRoot, err := h.arraysRoot(state.StateRoots, fieldparams.StateRootsLength, "StateRoots")
stateRootsRoot, err := arraysRoot(state.StateRoots, fieldparams.StateRootsLength)
if err != nil {
return nil, errors.Wrap(err, "could not compute state roots merkleization")
}
@@ -450,7 +412,7 @@ func (h *stateRootHasher) ComputeFieldRootsWithHasherBellatrix(ctx context.Conte
fieldRoots[10] = eth1DepositBuf[:]
// Validators slice root.
validatorsRoot, err := h.validatorRegistryRoot(state.Validators)
validatorsRoot, err := validatorRegistryRoot(state.Validators)
if err != nil {
return nil, errors.Wrap(err, "could not compute validator registry merkleization")
}
@@ -464,7 +426,7 @@ func (h *stateRootHasher) ComputeFieldRootsWithHasherBellatrix(ctx context.Conte
fieldRoots[12] = balancesRoot[:]
// RandaoMixes array root.
randaoRootsRoot, err := h.arraysRoot(state.RandaoMixes, fieldparams.RandaoMixesLength, "RandaoMixes")
randaoRootsRoot, err := arraysRoot(state.RandaoMixes, fieldparams.RandaoMixesLength)
if err != nil {
return nil, errors.Wrap(err, "could not compute randao roots merkleization")
}

View File

@@ -1,13 +0,0 @@
package stateutil_test
import (
"testing"
"github.com/prysmaticlabs/prysm/config/features"
)
func TestMain(m *testing.M) {
resetCfg := features.InitWithReset(&features.Flags{EnableSSZCache: true})
defer resetCfg()
m.Run()
}

View File

@@ -5,8 +5,10 @@ import (
"encoding/binary"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/config/features"
"github.com/prysmaticlabs/prysm/container/trie"
"github.com/prysmaticlabs/prysm/crypto/hash"
"github.com/prysmaticlabs/prysm/crypto/hash/htr"
"github.com/prysmaticlabs/prysm/encoding/ssz"
"github.com/prysmaticlabs/prysm/math"
)
@@ -61,25 +63,43 @@ func ReturnTrieLayerVariable(elements [][32]byte, length uint64) [][]*[32]byte {
layers[0] = transformedLeaves
buffer := bytes.NewBuffer([]byte{})
buffer.Grow(64)
for i := 0; i < int(depth); i++ {
oddNodeLength := len(layers[i])%2 == 1
if oddNodeLength {
zerohash := trie.ZeroHashes[i]
layers[i] = append(layers[i], &zerohash)
layerLen := len(layers[i])
oddNodeLength := layerLen%2 == 1
if features.Get().EnableVectorizedHTR {
if oddNodeLength {
zerohash := trie.ZeroHashes[i]
elements = append(elements, zerohash)
layerLen++
}
layers[i+1] = make([]*[32]byte, layerLen/2)
newElems := make([][32]byte, layerLen/2)
htr.VectorizedSha256(elements, newElems)
elements = newElems
for j := range elements {
layers[i+1][j] = &elements[j]
}
} else {
if oddNodeLength {
zerohash := trie.ZeroHashes[i]
layers[i] = append(layers[i], &zerohash)
}
updatedValues := make([]*[32]byte, 0, len(layers[i])/2)
for j := 0; j < len(layers[i]); j += 2 {
buffer.Write(layers[i][j][:])
buffer.Write(layers[i][j+1][:])
concat := hasher(buffer.Bytes())
updatedValues = append(updatedValues, &concat)
buffer.Reset()
}
// remove zerohash node from tree
if oddNodeLength {
layers[i] = layers[i][:len(layers[i])-1]
}
layers[i+1] = updatedValues
}
updatedValues := make([]*[32]byte, 0, len(layers[i])/2)
for j := 0; j < len(layers[i]); j += 2 {
buffer.Write(layers[i][j][:])
buffer.Write(layers[i][j+1][:])
concat := hasher(buffer.Bytes())
updatedValues = append(updatedValues, &concat)
buffer.Reset()
}
// remove zerohash node from tree
if oddNodeLength {
layers[i] = layers[i][:len(layers[i])-1]
}
layers[i+1] = updatedValues
}
return layers
}
@@ -277,18 +297,24 @@ func MerkleizeTrieLeaves(layers [][][32]byte, hashLayer [][32]byte,
chunkBuffer := bytes.NewBuffer([]byte{})
chunkBuffer.Grow(64)
for len(hashLayer) > 1 && i < len(layers) {
layer := make([][32]byte, len(hashLayer)/2)
if !math.IsPowerOf2(uint64(len(hashLayer))) {
return nil, nil, errors.Errorf("hash layer is a non power of 2: %d", len(hashLayer))
}
for j := 0; j < len(hashLayer); j += 2 {
chunkBuffer.Write(hashLayer[j][:])
chunkBuffer.Write(hashLayer[j+1][:])
hashedChunk := hasher(chunkBuffer.Bytes())
layer[j/2] = hashedChunk
chunkBuffer.Reset()
if features.Get().EnableVectorizedHTR {
newLayer := make([][32]byte, len(hashLayer)/2)
htr.VectorizedSha256(hashLayer, newLayer)
hashLayer = newLayer
} else {
layer := make([][32]byte, len(hashLayer)/2)
for j := 0; j < len(hashLayer); j += 2 {
chunkBuffer.Write(hashLayer[j][:])
chunkBuffer.Write(hashLayer[j+1][:])
hashedChunk := hasher(chunkBuffer.Bytes())
layer[j/2] = hashedChunk
chunkBuffer.Reset()
}
hashLayer = layer
}
hashLayer = layer
layers[i] = hashLayer
i++
}

View File

@@ -4,7 +4,9 @@ import (
"testing"
types "github.com/prysmaticlabs/eth2-types"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
"github.com/prysmaticlabs/prysm/config/features"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/crypto/hash"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
@@ -16,17 +18,58 @@ import (
func TestReturnTrieLayer_OK(t *testing.T) {
newState, _ := util.DeterministicGenesisState(t, 32)
root, err := stateutil.RootsArrayHashTreeRoot(newState.BlockRoots(), uint64(params.BeaconConfig().SlotsPerHistoricalRoot), "BlockRoots")
root, err := stateutil.RootsArrayHashTreeRoot(newState.BlockRoots(), uint64(params.BeaconConfig().SlotsPerHistoricalRoot))
require.NoError(t, err)
blockRts := newState.BlockRoots()
roots := make([][32]byte, 0, len(blockRts))
for _, rt := range blockRts {
roots = append(roots, bytesutil.ToBytes32(rt))
}
roots := retrieveBlockRoots(newState)
layers, err := stateutil.ReturnTrieLayer(roots, uint64(len(roots)))
assert.NoError(t, err)
newRoot := *layers[len(layers)-1][0]
assert.Equal(t, root, newRoot)
flags := &features.Flags{}
flags.EnableVectorizedHTR = true
reset := features.InitWithReset(flags)
defer reset()
layers, err = stateutil.ReturnTrieLayer(roots, uint64(len(roots)))
assert.NoError(t, err)
lastRoot := *layers[len(layers)-1][0]
assert.Equal(t, root, lastRoot)
}
func BenchmarkReturnTrieLayer_NormalAlgorithm(b *testing.B) {
newState, _ := util.DeterministicGenesisState(b, 32)
root, err := stateutil.RootsArrayHashTreeRoot(newState.BlockRoots(), uint64(params.BeaconConfig().SlotsPerHistoricalRoot))
require.NoError(b, err)
roots := retrieveBlockRoots(newState)
b.ResetTimer()
for i := 0; i < b.N; i++ {
layers, err := stateutil.ReturnTrieLayer(roots, uint64(len(roots)))
assert.NoError(b, err)
newRoot := *layers[len(layers)-1][0]
assert.Equal(b, root, newRoot)
}
}
func BenchmarkReturnTrieLayer_VectorizedAlgorithm(b *testing.B) {
flags := &features.Flags{}
flags.EnableVectorizedHTR = true
reset := features.InitWithReset(flags)
defer reset()
newState, _ := util.DeterministicGenesisState(b, 32)
root, err := stateutil.RootsArrayHashTreeRoot(newState.BlockRoots(), uint64(params.BeaconConfig().SlotsPerHistoricalRoot))
require.NoError(b, err)
roots := retrieveBlockRoots(newState)
b.ResetTimer()
for i := 0; i < b.N; i++ {
layers, err := stateutil.ReturnTrieLayer(roots, uint64(len(roots)))
assert.NoError(b, err)
newRoot := *layers[len(layers)-1][0]
assert.Equal(b, root, newRoot)
}
}
func TestReturnTrieLayerVariable_OK(t *testing.T) {
@@ -46,15 +89,73 @@ func TestReturnTrieLayerVariable_OK(t *testing.T) {
newRoot, err = stateutil.AddInMixin(newRoot, uint64(len(validators)))
require.NoError(t, err)
assert.Equal(t, root, newRoot)
flags := &features.Flags{}
flags.EnableVectorizedHTR = true
reset := features.InitWithReset(flags)
defer reset()
layers = stateutil.ReturnTrieLayerVariable(roots, params.BeaconConfig().ValidatorRegistryLimit)
lastRoot := *layers[len(layers)-1][0]
lastRoot, err = stateutil.AddInMixin(lastRoot, uint64(len(validators)))
require.NoError(t, err)
assert.Equal(t, root, lastRoot)
}
func BenchmarkReturnTrieLayerVariable_NormalAlgorithm(b *testing.B) {
newState, _ := util.DeterministicGenesisState(b, 16000)
root, err := stateutil.ValidatorRegistryRoot(newState.Validators())
require.NoError(b, err)
hasher := hash.CustomSHA256Hasher()
validators := newState.Validators()
roots := make([][32]byte, 0, len(validators))
for _, val := range validators {
rt, err := stateutil.ValidatorRootWithHasher(hasher, val)
require.NoError(b, err)
roots = append(roots, rt)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
layers := stateutil.ReturnTrieLayerVariable(roots, params.BeaconConfig().ValidatorRegistryLimit)
newRoot := *layers[len(layers)-1][0]
newRoot, err = stateutil.AddInMixin(newRoot, uint64(len(validators)))
require.NoError(b, err)
assert.Equal(b, root, newRoot)
}
}
func BenchmarkReturnTrieLayerVariable_VectorizedAlgorithm(b *testing.B) {
flags := &features.Flags{}
flags.EnableVectorizedHTR = true
reset := features.InitWithReset(flags)
defer reset()
newState, _ := util.DeterministicGenesisState(b, 16000)
root, err := stateutil.ValidatorRegistryRoot(newState.Validators())
require.NoError(b, err)
hasher := hash.CustomSHA256Hasher()
validators := newState.Validators()
roots := make([][32]byte, 0, len(validators))
for _, val := range validators {
rt, err := stateutil.ValidatorRootWithHasher(hasher, val)
require.NoError(b, err)
roots = append(roots, rt)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
layers := stateutil.ReturnTrieLayerVariable(roots, params.BeaconConfig().ValidatorRegistryLimit)
newRoot := *layers[len(layers)-1][0]
newRoot, err = stateutil.AddInMixin(newRoot, uint64(len(validators)))
require.NoError(b, err)
assert.Equal(b, root, newRoot)
}
}
func TestRecomputeFromLayer_FixedSizedArray(t *testing.T) {
newState, _ := util.DeterministicGenesisState(t, 32)
blockRts := newState.BlockRoots()
roots := make([][32]byte, 0, len(blockRts))
for _, rt := range blockRts {
roots = append(roots, bytesutil.ToBytes32(rt))
}
roots := retrieveBlockRoots(newState)
layers, err := stateutil.ReturnTrieLayer(roots, uint64(len(roots)))
require.NoError(t, err)
@@ -63,7 +164,7 @@ func TestRecomputeFromLayer_FixedSizedArray(t *testing.T) {
require.NoError(t, newState.UpdateBlockRootAtIndex(changedIdx[0], changedRoots[0]))
require.NoError(t, newState.UpdateBlockRootAtIndex(changedIdx[1], changedRoots[1]))
expectedRoot, err := stateutil.RootsArrayHashTreeRoot(newState.BlockRoots(), uint64(params.BeaconConfig().SlotsPerHistoricalRoot), "BlockRoots")
expectedRoot, err := stateutil.RootsArrayHashTreeRoot(newState.BlockRoots(), uint64(params.BeaconConfig().SlotsPerHistoricalRoot))
require.NoError(t, err)
root, _, err := stateutil.RecomputeFromLayer(changedRoots, changedIdx, layers)
require.NoError(t, err)
@@ -120,3 +221,12 @@ func TestMerkleizeTrieLeaves_BadHashLayer(t *testing.T) {
})
assert.ErrorContains(t, "hash layer is a non power of 2", err)
}
func retrieveBlockRoots(b state.BeaconState) [][32]byte {
blockRts := b.BlockRoots()
roots := make([][32]byte, 0, len(blockRts))
for _, rt := range blockRts {
roots = append(roots, bytesutil.ToBytes32(rt))
}
return roots
}

View File

@@ -4,8 +4,10 @@ import (
"encoding/binary"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/config/features"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
"github.com/prysmaticlabs/prysm/crypto/hash"
"github.com/prysmaticlabs/prysm/crypto/hash/htr"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/encoding/ssz"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
@@ -14,6 +16,16 @@ import (
// ValidatorRootWithHasher describes a method from which the hash tree root
// of a validator is returned.
func ValidatorRootWithHasher(hasher ssz.HashFn, validator *ethpb.Validator) ([32]byte, error) {
fieldRoots, err := ValidatorFieldRoots(hasher, validator)
if err != nil {
return [32]byte{}, err
}
return ssz.BitwiseMerkleizeArrays(hasher, fieldRoots, uint64(len(fieldRoots)), uint64(len(fieldRoots)))
}
// ValidatorFieldRoots describes a method from which the hash tree root
// of a validator is returned.
func ValidatorFieldRoots(hasher ssz.HashFn, validator *ethpb.Validator) ([][32]byte, error) {
var fieldRoots [][32]byte
if validator != nil {
pubkey := bytesutil.ToBytes48(validator.PublicKey)
@@ -40,18 +52,25 @@ func ValidatorRootWithHasher(hasher ssz.HashFn, validator *ethpb.Validator) ([32
binary.LittleEndian.PutUint64(withdrawalBuf[:8], uint64(validator.WithdrawableEpoch))
// Public key.
pubKeyChunks, err := ssz.Pack([][]byte{pubkey[:]})
pubKeyChunks, err := ssz.PackByChunk([][]byte{pubkey[:]})
if err != nil {
return [32]byte{}, err
return [][32]byte{}, err
}
pubKeyRoot, err := ssz.BitwiseMerkleize(hasher, pubKeyChunks, uint64(len(pubKeyChunks)), uint64(len(pubKeyChunks)))
if err != nil {
return [32]byte{}, err
var pubKeyRoot [32]byte
if features.Get().EnableVectorizedHTR {
outputChunk := make([][32]byte, 1)
htr.VectorizedSha256(pubKeyChunks, outputChunk)
pubKeyRoot = outputChunk[0]
} else {
pubKeyRoot, err = ssz.BitwiseMerkleizeArrays(hasher, pubKeyChunks, uint64(len(pubKeyChunks)), uint64(len(pubKeyChunks)))
if err != nil {
return [][32]byte{}, err
}
}
fieldRoots = [][32]byte{pubKeyRoot, withdrawCreds, effectiveBalanceBuf, slashBuf, activationEligibilityBuf,
activationBuf, exitBuf, withdrawalBuf}
}
return ssz.BitwiseMerkleizeArrays(hasher, fieldRoots, uint64(len(fieldRoots)), uint64(len(fieldRoots)))
return fieldRoots, nil
}
// Uint64ListRootWithRegistryLimit computes the HashTreeRoot Merkleization of
@@ -87,42 +106,3 @@ func Uint64ListRootWithRegistryLimit(balances []uint64) ([32]byte, error) {
binary.LittleEndian.PutUint64(balancesLengthRoot, uint64(len(balances)))
return ssz.MixInLength(balancesRootsRoot, balancesLengthRoot), nil
}
// validatorEncKey returns the encoded key in bytes of input `validator`,
// the returned key bytes can be used for caching purposes.
func validatorEncKey(validator *ethpb.Validator) []byte {
if validator == nil {
return nil
}
enc := make([]byte, 122)
pubkey := bytesutil.ToBytes48(validator.PublicKey)
copy(enc[0:48], pubkey[:])
withdrawCreds := bytesutil.ToBytes32(validator.WithdrawalCredentials)
copy(enc[48:80], withdrawCreds[:])
effectiveBalanceBuf := [32]byte{}
binary.LittleEndian.PutUint64(effectiveBalanceBuf[:8], validator.EffectiveBalance)
copy(enc[80:88], effectiveBalanceBuf[:8])
if validator.Slashed {
enc[88] = uint8(1)
} else {
enc[88] = uint8(0)
}
activationEligibilityBuf := [32]byte{}
binary.LittleEndian.PutUint64(activationEligibilityBuf[:8], uint64(validator.ActivationEligibilityEpoch))
copy(enc[89:97], activationEligibilityBuf[:8])
activationBuf := [32]byte{}
binary.LittleEndian.PutUint64(activationBuf[:8], uint64(validator.ActivationEpoch))
copy(enc[97:105], activationBuf[:8])
exitBuf := [32]byte{}
binary.LittleEndian.PutUint64(exitBuf[:8], uint64(validator.ExitEpoch))
copy(enc[105:113], exitBuf[:8])
withdrawalBuf := [32]byte{}
binary.LittleEndian.PutUint64(withdrawalBuf[:8], uint64(validator.WithdrawableEpoch))
copy(enc[113:121], withdrawalBuf[:8])
return enc
}

View File

@@ -4,15 +4,11 @@ import (
"context"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
"github.com/prysmaticlabs/prysm/config/features"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
// computeFieldRoots returns the hash tree root computations of every field in
// the beacon state as a list of 32 byte roots.
func computeFieldRoots(ctx context.Context, state *ethpb.BeaconState) ([][]byte, error) {
if features.Get().EnableSSZCache {
return stateutil.CachedHasher.ComputeFieldRootsWithHasherPhase0(ctx, state)
}
return stateutil.NocachedHasher.ComputeFieldRootsWithHasherPhase0(ctx, state)
return stateutil.ComputeFieldRootsWithHasherPhase0(ctx, state)
}

View File

@@ -177,6 +177,24 @@ func TestBeaconState_HashTreeRoot(t *testing.T) {
}
}
func BenchmarkBeaconState(b *testing.B) {
testState, _ := util.DeterministicGenesisState(b, 16000)
pbState, err := v1.ProtobufBeaconState(testState.InnerStateUnsafe())
require.NoError(b, err)
b.Run("Vectorized SHA256", func(b *testing.B) {
st, err := v1.InitializeFromProtoUnsafe(pbState)
require.NoError(b, err)
_, err = st.HashTreeRoot(context.Background())
assert.NoError(b, err)
})
b.Run("Current SHA256", func(b *testing.B) {
_, err := pbState.HashTreeRoot()
require.NoError(b, err)
})
}
func TestBeaconState_HashTreeRoot_FieldTrie(t *testing.T) {
testState, _ := util.DeterministicGenesisState(t, 64)

View File

@@ -4,15 +4,11 @@ import (
"context"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
"github.com/prysmaticlabs/prysm/config/features"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
// computeFieldRoots returns the hash tree root computations of every field in
// the beacon state as a list of 32 byte roots.
func computeFieldRoots(ctx context.Context, state *ethpb.BeaconStateAltair) ([][]byte, error) {
if features.Get().EnableSSZCache {
return stateutil.CachedHasher.ComputeFieldRootsWithHasherAltair(ctx, state)
}
return stateutil.NocachedHasher.ComputeFieldRootsWithHasherAltair(ctx, state)
return stateutil.ComputeFieldRootsWithHasherAltair(ctx, state)
}

View File

@@ -4,15 +4,11 @@ import (
"context"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
"github.com/prysmaticlabs/prysm/config/features"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
// computeFieldRoots returns the hash tree root computations of every field in
// the beacon state as a list of 32 byte roots.
func computeFieldRoots(ctx context.Context, state *ethpb.BeaconStateBellatrix) ([][]byte, error) {
if features.Get().EnableSSZCache {
return stateutil.CachedHasher.ComputeFieldRootsWithHasherBellatrix(ctx, state)
}
return stateutil.NocachedHasher.ComputeFieldRootsWithHasherBellatrix(ctx, state)
return stateutil.ComputeFieldRootsWithHasherBellatrix(ctx, state)
}

View File

@@ -38,7 +38,7 @@ func TestAppendBeyondIndicesLimit(t *testing.T) {
StateRoot: make([]byte, 32),
ReceiptRoot: make([]byte, 32),
LogsBloom: make([]byte, 256),
Random: make([]byte, 32),
PrevRandao: make([]byte, 32),
BaseFeePerGas: make([]byte, 32),
BlockHash: make([]byte, 32),
TransactionsRoot: make([]byte, 32),
@@ -122,7 +122,7 @@ func TestBeaconState_AppendBalanceWithTrie(t *testing.T) {
StateRoot: make([]byte, 32),
ReceiptRoot: make([]byte, 32),
LogsBloom: make([]byte, 256),
Random: make([]byte, 32),
PrevRandao: make([]byte, 32),
BaseFeePerGas: make([]byte, 32),
BlockHash: make([]byte, 32),
TransactionsRoot: make([]byte, 32),

View File

@@ -86,7 +86,7 @@ go_library(
"//crypto/bls:go_default_library",
"//crypto/rand:go_default_library",
"//encoding/bytesutil:go_default_library",
"//encoding/ssz:go_default_library",
"//encoding/ssz/equality:go_default_library",
"//monitoring/tracing:go_default_library",
"//network/forks:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
@@ -195,7 +195,7 @@ go_test(
"//crypto/bls:go_default_library",
"//crypto/rand:go_default_library",
"//encoding/bytesutil:go_default_library",
"//encoding/ssz:go_default_library",
"//encoding/ssz/equality:go_default_library",
"//network/forks:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/attestation:go_default_library",

View File

@@ -15,7 +15,7 @@ import (
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/crypto/rand"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/encoding/ssz"
"github.com/prysmaticlabs/prysm/encoding/ssz/equality"
"github.com/prysmaticlabs/prysm/monitoring/tracing"
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
"github.com/prysmaticlabs/prysm/time/slots"
@@ -328,7 +328,7 @@ func (s *Service) deleteBlockFromPendingQueue(slot types.Slot, b block.SignedBea
newBlks := make([]block.SignedBeaconBlock, 0, len(blks))
for _, blk := range blks {
if ssz.DeepEqual(blk.Proto(), b.Proto()) {
if equality.DeepEqual(blk.Proto(), b.Proto()) {
continue
}
newBlks = append(newBlks, blk)

View File

@@ -17,7 +17,7 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/p2p"
p2ptest "github.com/prysmaticlabs/prysm/beacon-chain/p2p/testing"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/encoding/ssz"
"github.com/prysmaticlabs/prysm/encoding/ssz/equality"
pb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/metadata"
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper"
@@ -125,7 +125,7 @@ func TestMetadataRPCHandler_SendsMetadata(t *testing.T) {
metadata, err := r.sendMetaDataRequest(context.Background(), p2.BHost.ID())
assert.NoError(t, err)
if !ssz.DeepEqual(metadata.InnerObject(), p2.LocalMetadata.InnerObject()) {
if !equality.DeepEqual(metadata.InnerObject(), p2.LocalMetadata.InnerObject()) {
t.Fatalf("MetadataV0 unequal, received %v but wanted %v", metadata, p2.LocalMetadata)
}
@@ -213,7 +213,7 @@ func TestMetadataRPCHandler_SendsMetadataAltair(t *testing.T) {
metadata, err := r.sendMetaDataRequest(context.Background(), p2.BHost.ID())
assert.NoError(t, err)
if !ssz.DeepEqual(metadata.InnerObject(), p2.LocalMetadata.InnerObject()) {
if !equality.DeepEqual(metadata.InnerObject(), p2.LocalMetadata.InnerObject()) {
t.Fatalf("MetadataV1 unequal, received %v but wanted %v", metadata, p2.LocalMetadata)
}

View File

@@ -23,6 +23,18 @@ var (
Usage: "An http endpoint for an Ethereum execution node",
Value: "",
}
// ExecutionJWTSecretFlag provides a path to a file containing a hex-encoded string representing a 32 byte secret
// used to authenticate with an execution node via HTTP. This is required if using an HTTP connection, otherwise all requests
// to execution nodes for consensus-related calls will fail. This is not required if using an IPC connection.
ExecutionJWTSecretFlag = &cli.StringFlag{
Name: "jwt-secret",
Usage: "REQUIRED if connecting to an execution node via HTTP. Provides a path to a file containing " +
"a hex-encoded string representing a 32 byte secret used for authentication with an execution node via " +
"HTTP. If this is not set, all requests to execution nodes via HTTP for consensus-related calls will " +
"fail, which will prevent your validators from performing their duties. " +
"This is not required if using an IPC connection.",
Value: "",
}
// FallbackWeb3ProviderFlag provides a fallback endpoint to an ETH 1.0 RPC.
FallbackWeb3ProviderFlag = &cli.StringSliceFlag{
Name: "fallback-web3provider",

View File

@@ -34,6 +34,7 @@ var appFlags = []cli.Flag{
flags.DepositContractFlag,
flags.HTTPWeb3ProviderFlag,
flags.ExecutionProviderFlag,
flags.ExecutionJWTSecretFlag,
flags.FallbackWeb3ProviderFlag,
flags.RPCHost,
flags.RPCPort,
@@ -117,6 +118,7 @@ var appFlags = []cli.Flag{
cmd.RestoreTargetDirFlag,
cmd.BoltMMapInitialSizeFlag,
cmd.ValidatorMonitorIndicesFlag,
cmd.ApiTimeoutFlag,
}
func init() {
@@ -231,11 +233,11 @@ func startNode(ctx *cli.Context) error {
blockchainFlagOpts, err := blockchaincmd.FlagOptions(ctx)
if err != nil {
return nil
return err
}
powchainFlagOpts, err := powchaincmd.FlagOptions(ctx)
if err != nil {
return nil
return err
}
opts := []node.Option{
node.WithBlockchainFlagOptions(blockchainFlagOpts),

View File

@@ -11,6 +11,8 @@ go_library(
deps = [
"//beacon-chain/powchain:go_default_library",
"//cmd/beacon-chain/flags:go_default_library",
"//io/file:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@com_github_urfave_cli_v2//:go_default_library",
],
@@ -22,6 +24,8 @@ go_test(
embed = [":go_default_library"],
deps = [
"//cmd/beacon-chain/flags:go_default_library",
"//encoding/bytesutil:go_default_library",
"//io/file:go_default_library",
"//testing/assert:go_default_library",
"//testing/require:go_default_library",
"@com_github_sirupsen_logrus//hooks/test:go_default_library",

View File

@@ -1,8 +1,14 @@
package powchaincmd
import (
"encoding/hex"
"fmt"
"strings"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/beacon-chain/powchain"
"github.com/prysmaticlabs/prysm/cmd/beacon-chain/flags"
"github.com/prysmaticlabs/prysm/io/file"
"github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
)
@@ -13,6 +19,10 @@ var log = logrus.WithField("prefix", "cmd-powchain")
func FlagOptions(c *cli.Context) ([]powchain.Option, error) {
endpoints := parsePowchainEndpoints(c)
executionEndpoint := parseExecutionEndpoint(c)
jwtSecret, err := parseJWTSecretFromFile(c)
if err != nil {
return nil, errors.Wrap(err, "could not read JWT secret file for authenticating execution API")
}
opts := []powchain.Option{
powchain.WithHttpEndpoints(endpoints),
powchain.WithEth1HeaderRequestLimit(c.Uint64(flags.Eth1HeaderReqLimit.Name)),
@@ -20,9 +30,43 @@ func FlagOptions(c *cli.Context) ([]powchain.Option, error) {
if executionEndpoint != "" {
opts = append(opts, powchain.WithExecutionEndpoint(executionEndpoint))
}
if len(jwtSecret) > 0 {
opts = append(opts, powchain.WithExecutionClientJWTSecret(jwtSecret))
}
return opts, nil
}
// Parses a JWT secret from a file path. This secret is required when connecting to execution nodes
// over HTTP, and must be the same one used in Prysm and the execution node server Prysm is connecting to.
// The engine API specification here https://github.com/ethereum/execution-apis/blob/main/src/engine/authentication.md
// Explains how we should validate this secret and the format of the file a user can specify.
//
// The secret must be stored as a hex-encoded string within a file in the filesystem.
// If the --jwt-secret flag is provided to Prysm, but the file cannot be read, or does not contain a hex-encoded
// key of at least 256 bits, the client should treat this as an error and abort the startup.
func parseJWTSecretFromFile(c *cli.Context) ([]byte, error) {
jwtSecretFile := c.String(flags.ExecutionJWTSecretFlag.Name)
if jwtSecretFile == "" {
return nil, nil
}
enc, err := file.ReadFileAsBytes(jwtSecretFile)
if err != nil {
return nil, err
}
strData := strings.TrimSpace(string(enc))
if len(strData) == 0 {
return nil, fmt.Errorf("provided JWT secret in file %s cannot be empty", jwtSecretFile)
}
secret, err := hex.DecodeString(strings.TrimPrefix(strData, "0x"))
if err != nil {
return nil, err
}
if len(secret) < 32 {
return nil, errors.New("provided JWT secret should be a hex string of at least 32 bytes")
}
return secret, nil
}
func parsePowchainEndpoints(c *cli.Context) []string {
if c.String(flags.HTTPWeb3ProviderFlag.Name) == "" && len(c.StringSlice(flags.FallbackWeb3ProviderFlag.Name)) == 0 {
log.Error(

View File

@@ -2,9 +2,14 @@ package powchaincmd
import (
"flag"
"fmt"
"os"
"path/filepath"
"testing"
"github.com/prysmaticlabs/prysm/cmd/beacon-chain/flags"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/io/file"
"github.com/prysmaticlabs/prysm/testing/assert"
"github.com/prysmaticlabs/prysm/testing/require"
logTest "github.com/sirupsen/logrus/hooks/test"
@@ -27,6 +32,92 @@ func TestPowchainCmd(t *testing.T) {
assert.DeepEqual(t, []string{"primary", "fallback1", "fallback2"}, endpoints)
}
func Test_parseJWTSecretFromFile(t *testing.T) {
t.Run("no flag value specified leads to nil secret", func(t *testing.T) {
app := cli.App{}
set := flag.NewFlagSet("test", 0)
set.String(flags.ExecutionJWTSecretFlag.Name, "", "")
ctx := cli.NewContext(&app, set, nil)
secret, err := parseJWTSecretFromFile(ctx)
require.NoError(t, err)
require.Equal(t, true, secret == nil)
})
t.Run("flag specified but no file found", func(t *testing.T) {
app := cli.App{}
set := flag.NewFlagSet("test", 0)
set.String(flags.ExecutionJWTSecretFlag.Name, "/tmp/askdjkajsd", "")
ctx := cli.NewContext(&app, set, nil)
_, err := parseJWTSecretFromFile(ctx)
require.ErrorContains(t, "no such file", err)
})
t.Run("empty string in file", func(t *testing.T) {
app := cli.App{}
set := flag.NewFlagSet("test", 0)
fullPath := filepath.Join(os.TempDir(), "foohex")
require.NoError(t, file.WriteFile(fullPath, []byte{}))
t.Cleanup(func() {
if err := os.RemoveAll(fullPath); err != nil {
t.Fatalf("Could not delete temp dir: %v", err)
}
})
set.String(flags.ExecutionJWTSecretFlag.Name, fullPath, "")
ctx := cli.NewContext(&app, set, nil)
_, err := parseJWTSecretFromFile(ctx)
require.ErrorContains(t, "cannot be empty", err)
})
t.Run("less than 32 bytes", func(t *testing.T) {
app := cli.App{}
set := flag.NewFlagSet("test", 0)
fullPath := filepath.Join(os.TempDir(), "foohex")
secret := bytesutil.PadTo([]byte("foo"), 31)
hexData := fmt.Sprintf("%#x", secret)
require.NoError(t, file.WriteFile(fullPath, []byte(hexData)))
t.Cleanup(func() {
if err := os.RemoveAll(fullPath); err != nil {
t.Fatalf("Could not delete temp dir: %v", err)
}
})
set.String(flags.ExecutionJWTSecretFlag.Name, fullPath, "")
ctx := cli.NewContext(&app, set, nil)
_, err := parseJWTSecretFromFile(ctx)
require.ErrorContains(t, "should be a hex string of at least 32 bytes", err)
})
t.Run("bad data", func(t *testing.T) {
app := cli.App{}
set := flag.NewFlagSet("test", 0)
fullPath := filepath.Join(os.TempDir(), "foohex")
secret := []byte("foo")
require.NoError(t, file.WriteFile(fullPath, secret))
t.Cleanup(func() {
if err := os.RemoveAll(fullPath); err != nil {
t.Fatalf("Could not delete temp dir: %v", err)
}
})
set.String(flags.ExecutionJWTSecretFlag.Name, fullPath, "")
ctx := cli.NewContext(&app, set, nil)
_, err := parseJWTSecretFromFile(ctx)
require.ErrorContains(t, "invalid byte", err)
})
t.Run("correct format", func(t *testing.T) {
app := cli.App{}
set := flag.NewFlagSet("test", 0)
fullPath := filepath.Join(os.TempDir(), "foohex")
secret := bytesutil.ToBytes32([]byte("foo"))
secretHex := fmt.Sprintf("%#x", secret)
require.NoError(t, file.WriteFile(fullPath, []byte(secretHex)))
t.Cleanup(func() {
if err := os.RemoveAll(fullPath); err != nil {
t.Fatalf("Could not delete temp dir: %v", err)
}
})
set.String(flags.ExecutionJWTSecretFlag.Name, fullPath, "")
ctx := cli.NewContext(&app, set, nil)
got, err := parseJWTSecretFromFile(ctx)
require.NoError(t, err)
require.DeepEqual(t, secret[:], got)
})
}
func TestPowchainPreregistration_EmptyWeb3Provider(t *testing.T) {
hook := logTest.NewGlobal()
app := cli.App{}

View File

@@ -74,6 +74,7 @@ var appHelpFlagGroups = []flagGroup{
cmd.RestoreTargetDirFlag,
cmd.BoltMMapInitialSizeFlag,
cmd.ValidatorMonitorIndicesFlag,
cmd.ApiTimeoutFlag,
},
},
{
@@ -107,6 +108,7 @@ var appHelpFlagGroups = []flagGroup{
flags.GPRCGatewayCorsDomain,
flags.HTTPWeb3ProviderFlag,
flags.ExecutionProviderFlag,
flags.ExecutionJWTSecretFlag,
flags.FallbackWeb3ProviderFlag,
flags.SetGCPercent,
flags.HeadSync,

View File

@@ -249,6 +249,12 @@ var (
Usage: "Specifies the size in bytes of bolt db's mmap syscall allocation",
Value: 536870912, // 512 Mb as a default value.
}
// ApiTimeoutFlag specifies the timeout value for API requests in seconds. A timeout of zero means no timeout.
ApiTimeoutFlag = &cli.IntFlag{
Name: "api-timeout",
Usage: "Specifies the timeout value for API requests in seconds",
Value: 120,
}
)
// LoadFlagsFromConfig sets flags values from config file if ConfigFileFlag is set.

View File

@@ -96,6 +96,7 @@ var appFlags = []cli.Flag{
cmd.ChainConfigFileFlag,
cmd.GrpcMaxCallRecvMsgSizeFlag,
cmd.BoltMMapInitialSizeFlag,
cmd.ApiTimeoutFlag,
debug.PProfFlag,
debug.PProfAddrFlag,
debug.PProfPortFlag,

View File

@@ -66,6 +66,7 @@ var appHelpFlagGroups = []flagGroup{
cmd.GrpcMaxCallRecvMsgSizeFlag,
cmd.AcceptTosFlag,
cmd.BoltMMapInitialSizeFlag,
cmd.ApiTimeoutFlag,
},
},
{

View File

@@ -61,7 +61,6 @@ type Flags struct {
DisableBroadcastSlashings bool // DisableBroadcastSlashings disables p2p broadcasting of proposer and attester slashings.
// Cache toggles.
EnableSSZCache bool // EnableSSZCache see https://github.com/prysmaticlabs/prysm/pull/4558.
EnableActiveBalanceCache bool // EnableActiveBalanceCache enables active balance cache.
// Bug fixes related flags.
@@ -75,7 +74,8 @@ type Flags struct {
CorrectlyInsertOrphanedAtts bool
CorrectlyPruneCanonicalAtts bool
EnableNativeState bool // EnableNativeState defines whether the beacon state will be represented as a pure Go struct or a Go struct that wraps a proto struct.
EnableNativeState bool // EnableNativeState defines whether the beacon state will be represented as a pure Go struct or a Go struct that wraps a proto struct.
EnableVectorizedHTR bool // EnableVectorizedHTR specifies whether the beacon state will use the optimized sha256 routines.
// KeystoreImportDebounceInterval specifies the time duration the validator waits to reload new keys if they have
// changed on disk. This feature is for advanced use cases only.
@@ -151,8 +151,6 @@ func ConfigureBeaconChain(ctx *cli.Context) {
cfg.WriteSSZStateTransitions = true
}
cfg.EnableSSZCache = true
if ctx.IsSet(disableGRPCConnectionLogging.Name) {
logDisabled(disableGRPCConnectionLogging)
cfg.DisableGRPCConnectionLogs = true
@@ -225,6 +223,10 @@ func ConfigureBeaconChain(ctx *cli.Context) {
logEnabled(enableNativeState)
cfg.EnableNativeState = true
}
if ctx.Bool(enableVecHTR.Name) {
logEnabled(enableVecHTR)
cfg.EnableVectorizedHTR = true
}
Init(cfg)
}

View File

@@ -134,11 +134,16 @@ var (
Name: "enable-native-state",
Usage: "Enables representing the beacon state as a pure Go struct.",
}
enableVecHTR = &cli.BoolFlag{
Name: "enable-vectorized-htr",
Usage: "Enables new go sha256 library which utilizes optimized routines for merkle trees",
}
)
// devModeFlags holds list of flags that are set when development mode is on.
var devModeFlags = []cli.Flag{
enablePeerScorer,
enableVecHTR,
}
// ValidatorFlags contains a list of all the feature flags that apply to the validator client.
@@ -183,6 +188,7 @@ var BeaconChainFlags = append(deprecatedFlags, []cli.Flag{
disableBatchGossipVerification,
disableBalanceTrieComputation,
enableNativeState,
enableVecHTR,
}...)
// E2EBeaconChainFlags contains a list of the beacon chain feature flags to be tested in E2E.

View File

@@ -0,0 +1,9 @@
load("@prysm//tools/go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["hashtree.go"],
importpath = "github.com/prysmaticlabs/prysm/crypto/hash/htr",
visibility = ["//visibility:public"],
deps = ["@com_github_prysmaticlabs_gohashtree//:go_default_library"],
)

View File

@@ -0,0 +1,17 @@
package htr
import (
"github.com/prysmaticlabs/gohashtree"
)
// VectorizedSha256 takes a list of roots and hashes them using CPU
// specific vector instructions. Depending on host machine's specific
// hardware configuration, using this routine can lead to a significant
// performance improvement compared to the default method of hashing
// lists.
func VectorizedSha256(inputList [][32]byte, outputList [][32]byte) {
err := gohashtree.Hash(outputList, inputList)
if err != nil {
panic(err)
}
}

View File

@@ -1150,12 +1150,11 @@ def prysm_deps():
sum = "h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=",
version = "v0.0.0-20200121045136-8c9f03a8e57e",
)
go_repository(
name = "com_github_golang_jwt_jwt",
importpath = "github.com/golang-jwt/jwt",
sum = "h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=",
version = "v3.2.2+incompatible",
name = "com_github_golang_jwt_jwt_v4",
importpath = "github.com/golang-jwt/jwt/v4",
sum = "h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog=",
version = "v4.3.0",
)
go_repository(
name = "com_github_golang_lint",
@@ -2983,6 +2982,13 @@ def prysm_deps():
sum = "h1:0tVE4tdWQK9ZpYygoV7+vS6QkDvQVySboMVEIxBJmXw=",
version = "v0.0.0-20210809151128-385d8c5e3fb7",
)
go_repository(
name = "com_github_prysmaticlabs_gohashtree",
importpath = "github.com/prysmaticlabs/gohashtree",
sum = "h1:qVXMFNUGWbPpP7986YPsmL84A54oY7b/N+SOIBS3i5w=",
version = "v0.0.0-20220208111633-0606f58df32f",
)
go_repository(
name = "com_github_prysmaticlabs_prombbolt",
importpath = "github.com/prysmaticlabs/prombbolt",

View File

@@ -3,7 +3,6 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = [
"deep_equal.go",
"hashers.go",
"helpers.go",
"htrutils.go",
@@ -12,16 +11,16 @@ go_library(
importpath = "github.com/prysmaticlabs/prysm/encoding/ssz",
visibility = ["//visibility:public"],
deps = [
"//config/features:go_default_library",
"//config/fieldparams:go_default_library",
"//container/trie:go_default_library",
"//crypto/hash:go_default_library",
"//crypto/hash/htr:go_default_library",
"//encoding/bytesutil:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"@com_github_minio_sha256_simd//:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_prysmaticlabs_eth2_types//:go_default_library",
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
"@org_golang_google_protobuf//proto:go_default_library",
],
)
@@ -29,7 +28,6 @@ go_test(
name = "go_default_test",
size = "small",
srcs = [
"deep_equal_test.go",
"hashers_test.go",
"helpers_test.go",
"htrutils_test.go",

View File

@@ -0,0 +1,22 @@
load("@prysm//tools/go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = ["deep_equal.go"],
importpath = "github.com/prysmaticlabs/prysm/encoding/ssz/equality",
visibility = ["//visibility:public"],
deps = [
"@com_github_prysmaticlabs_eth2_types//:go_default_library",
"@org_golang_google_protobuf//proto:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["deep_equal_test.go"],
deps = [
":go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//testing/assert:go_default_library",
],
)

View File

@@ -1,4 +1,4 @@
package ssz
package equality
import (
"reflect"

View File

@@ -1,34 +1,34 @@
package ssz_test
package equality_test
import (
"testing"
"github.com/prysmaticlabs/prysm/encoding/ssz"
"github.com/prysmaticlabs/prysm/encoding/ssz/equality"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/testing/assert"
)
func TestDeepEqualBasicTypes(t *testing.T) {
assert.Equal(t, true, ssz.DeepEqual(true, true))
assert.Equal(t, false, ssz.DeepEqual(true, false))
assert.Equal(t, true, equality.DeepEqual(true, true))
assert.Equal(t, false, equality.DeepEqual(true, false))
assert.Equal(t, true, ssz.DeepEqual(byte(222), byte(222)))
assert.Equal(t, false, ssz.DeepEqual(byte(222), byte(111)))
assert.Equal(t, true, equality.DeepEqual(byte(222), byte(222)))
assert.Equal(t, false, equality.DeepEqual(byte(222), byte(111)))
assert.Equal(t, true, ssz.DeepEqual(uint64(1234567890), uint64(1234567890)))
assert.Equal(t, false, ssz.DeepEqual(uint64(1234567890), uint64(987653210)))
assert.Equal(t, true, equality.DeepEqual(uint64(1234567890), uint64(1234567890)))
assert.Equal(t, false, equality.DeepEqual(uint64(1234567890), uint64(987653210)))
assert.Equal(t, true, ssz.DeepEqual("hello", "hello"))
assert.Equal(t, false, ssz.DeepEqual("hello", "world"))
assert.Equal(t, true, equality.DeepEqual("hello", "hello"))
assert.Equal(t, false, equality.DeepEqual("hello", "world"))
assert.Equal(t, true, ssz.DeepEqual([3]byte{1, 2, 3}, [3]byte{1, 2, 3}))
assert.Equal(t, false, ssz.DeepEqual([3]byte{1, 2, 3}, [3]byte{1, 2, 4}))
assert.Equal(t, true, equality.DeepEqual([3]byte{1, 2, 3}, [3]byte{1, 2, 3}))
assert.Equal(t, false, equality.DeepEqual([3]byte{1, 2, 3}, [3]byte{1, 2, 4}))
var nilSlice1, nilSlice2 []byte
assert.Equal(t, true, ssz.DeepEqual(nilSlice1, nilSlice2))
assert.Equal(t, true, ssz.DeepEqual(nilSlice1, []byte{}))
assert.Equal(t, true, ssz.DeepEqual([]byte{1, 2, 3}, []byte{1, 2, 3}))
assert.Equal(t, false, ssz.DeepEqual([]byte{1, 2, 3}, []byte{1, 2, 4}))
assert.Equal(t, true, equality.DeepEqual(nilSlice1, nilSlice2))
assert.Equal(t, true, equality.DeepEqual(nilSlice1, []byte{}))
assert.Equal(t, true, equality.DeepEqual([]byte{1, 2, 3}, []byte{1, 2, 3}))
assert.Equal(t, false, equality.DeepEqual([]byte{1, 2, 3}, []byte{1, 2, 4}))
}
func TestDeepEqualStructs(t *testing.T) {
@@ -39,8 +39,8 @@ func TestDeepEqualStructs(t *testing.T) {
store1 := Store{uint64(1234), nil}
store2 := Store{uint64(1234), []byte{}}
store3 := Store{uint64(4321), []byte{}}
assert.Equal(t, true, ssz.DeepEqual(store1, store2))
assert.Equal(t, false, ssz.DeepEqual(store1, store3))
assert.Equal(t, true, equality.DeepEqual(store1, store2))
assert.Equal(t, false, equality.DeepEqual(store1, store3))
}
func TestDeepEqualStructs_Unexported(t *testing.T) {
@@ -53,14 +53,14 @@ func TestDeepEqualStructs_Unexported(t *testing.T) {
store2 := Store{uint64(1234), []byte{}, "hi there"}
store3 := Store{uint64(4321), []byte{}, "wow"}
store4 := Store{uint64(4321), []byte{}, "bow wow"}
assert.Equal(t, true, ssz.DeepEqual(store1, store2))
assert.Equal(t, false, ssz.DeepEqual(store1, store3))
assert.Equal(t, false, ssz.DeepEqual(store3, store4))
assert.Equal(t, true, equality.DeepEqual(store1, store2))
assert.Equal(t, false, equality.DeepEqual(store1, store3))
assert.Equal(t, false, equality.DeepEqual(store3, store4))
}
func TestDeepEqualProto(t *testing.T) {
var fork1, fork2 *ethpb.Fork
assert.Equal(t, true, ssz.DeepEqual(fork1, fork2))
assert.Equal(t, true, equality.DeepEqual(fork1, fork2))
fork1 = &ethpb.Fork{
PreviousVersion: []byte{123},
@@ -72,8 +72,8 @@ func TestDeepEqualProto(t *testing.T) {
CurrentVersion: []byte{125},
Epoch: 1234567890,
}
assert.Equal(t, true, ssz.DeepEqual(fork1, fork1))
assert.Equal(t, false, ssz.DeepEqual(fork1, fork2))
assert.Equal(t, true, equality.DeepEqual(fork1, fork1))
assert.Equal(t, false, equality.DeepEqual(fork1, fork2))
checkpoint1 := &ethpb.Checkpoint{
Epoch: 1234567890,
@@ -83,7 +83,7 @@ func TestDeepEqualProto(t *testing.T) {
Epoch: 1234567890,
Root: nil,
}
assert.Equal(t, true, ssz.DeepEqual(checkpoint1, checkpoint2))
assert.Equal(t, true, equality.DeepEqual(checkpoint1, checkpoint2))
}
func Test_IsProto(t *testing.T) {
@@ -125,7 +125,7 @@ func Test_IsProto(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := ssz.IsProto(tt.item); got != tt.want {
if got := equality.IsProto(tt.item); got != tt.want {
t.Errorf("isProtoSlice() = %v, want %v", got, tt.want)
}
})

View File

@@ -8,6 +8,7 @@ import (
"github.com/minio/sha256-simd"
"github.com/pkg/errors"
"github.com/prysmaticlabs/go-bitfield"
"github.com/prysmaticlabs/prysm/config/features"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
)
@@ -50,6 +51,9 @@ func BitwiseMerkleize(hasher HashFn, chunks [][]byte, count, limit uint64) ([32]
if count > limit {
return [32]byte{}, errors.New("merkleizing list that is too large, over limit")
}
if features.Get().EnableVectorizedHTR {
return MerkleizeList(chunks, limit), nil
}
hashFn := NewHasherFunc(hasher)
leafIndexer := func(i uint64) []byte {
return chunks[i]
@@ -62,6 +66,9 @@ func BitwiseMerkleizeArrays(hasher HashFn, chunks [][32]byte, count, limit uint6
if count > limit {
return [32]byte{}, errors.New("merkleizing list that is too large, over limit")
}
if features.Get().EnableVectorizedHTR {
return MerkleizeVector(chunks, limit), nil
}
hashFn := NewHasherFunc(hasher)
leafIndexer := func(i uint64) []byte {
return chunks[i][:]

View File

@@ -2,6 +2,7 @@ package ssz
import (
"github.com/prysmaticlabs/prysm/container/trie"
"github.com/prysmaticlabs/prysm/crypto/hash/htr"
)
// Merkleize.go is mostly a directly copy of the same filename from
@@ -34,8 +35,8 @@ func Depth(v uint64) (out uint8) {
// Then adding 1 to it to not get the index of the first bit, but the length of the bits (depth of tree)
// Zero is a special case, it has a 0 depth.
// Example:
// (in out): (0 0), (1 1), (2 1), (3 2), (4 2), (5 3), (6 3), (7 3), (8 3), (9 4)
if v == 0 {
// (in out): (0 0), (1 0), (2 1), (3 2), (4 2), (5 3), (6 3), (7 3), (8 3), (9 4)
if v <= 1 {
return 0
}
v--
@@ -196,3 +197,40 @@ func ConstructProof(hasher Hasher, count, limit uint64, leaf func(i uint64) []by
return
}
// MerkleizeVector uses our optimized routine to hash a list of 32-byte
// elements.
func MerkleizeVector(elements [][32]byte, length uint64) [32]byte {
depth := Depth(length)
// Return zerohash at depth
if len(elements) == 0 {
return trie.ZeroHashes[depth]
}
for i := 0; i < int(depth); i++ {
layerLen := len(elements)
oddNodeLength := layerLen%2 == 1
if oddNodeLength {
zerohash := trie.ZeroHashes[i]
elements = append(elements, zerohash)
}
outputLen := len(elements) / 2
htr.VectorizedSha256(elements, elements)
elements = elements[:outputLen]
}
return elements[0]
}
// MerkleizeList uses our optimized routine to hash a 2d-list of
// elements.
func MerkleizeList(elements [][]byte, length uint64) [32]byte {
depth := Depth(length)
// Return zerohash at depth
if len(elements) == 0 {
return trie.ZeroHashes[depth]
}
newElems := make([][32]byte, len(elements))
for i := range elements {
copy(newElems[i][:], elements[i])
}
return MerkleizeVector(newElems, length)
}

View File

@@ -112,3 +112,7 @@ func TestConstructProofNormalPath(t *testing.T) {
assert.DeepEqual(t, result[i], v)
}
}
func TestDepthOfOne(t *testing.T) {
assert.Equal(t, uint8(0), ssz.Depth(1))
}

3
go.mod
View File

@@ -17,7 +17,7 @@ require (
github.com/ghodss/yaml v1.0.0
github.com/go-yaml/yaml v2.1.0+incompatible
github.com/gogo/protobuf v1.3.2
github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/golang-jwt/jwt/v4 v4.3.0
github.com/golang/gddo v0.0.0-20200528160355-8d077c1d8f4c
github.com/golang/mock v1.6.0
github.com/golang/protobuf v1.5.2
@@ -253,6 +253,7 @@ require (
github.com/holiman/uint256 v1.2.0
github.com/peterh/liner v1.2.0 // indirect
github.com/prometheus/tsdb v0.10.0 // indirect
github.com/prysmaticlabs/gohashtree v0.0.0-20220208111633-0606f58df32f
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881 // indirect
google.golang.org/api v0.34.0 // indirect
google.golang.org/appengine v1.6.7 // indirect

6
go.sum
View File

@@ -355,8 +355,8 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog=
github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/gddo v0.0.0-20200528160355-8d077c1d8f4c h1:HoqgYR60VYu5+0BuG6pjeGp7LKEPZnHt+dUClx9PeIs=
github.com/golang/gddo v0.0.0-20200528160355-8d077c1d8f4c/go.mod h1:sam69Hju0uq+5uvLJUMDlsKlQ21Vrs1Kd/1YFPNYdOU=
@@ -1123,6 +1123,8 @@ github.com/prysmaticlabs/fastssz v0.0.0-20220110145812-fafb696cae88/go.mod h1:AS
github.com/prysmaticlabs/go-bitfield v0.0.0-20210108222456-8e92c3709aa0/go.mod h1:hCwmef+4qXWjv0jLDbQdWnL0Ol7cS7/lCSS26WR+u6s=
github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7 h1:0tVE4tdWQK9ZpYygoV7+vS6QkDvQVySboMVEIxBJmXw=
github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7/go.mod h1:wmuf/mdK4VMD+jA9ThwcUKjg3a2XWM9cVfFYjDyY4j4=
github.com/prysmaticlabs/gohashtree v0.0.0-20220208111633-0606f58df32f h1:qVXMFNUGWbPpP7986YPsmL84A54oY7b/N+SOIBS3i5w=
github.com/prysmaticlabs/gohashtree v0.0.0-20220208111633-0606f58df32f/go.mod h1:4pWaT30XoEx1j8KNJf3TV+E3mQkaufn7mf+jRNb/Fuk=
github.com/prysmaticlabs/grpc-gateway/v2 v2.3.1-0.20210702154020-550e1cd83ec1 h1:xcu59yYL6AWWTl6jtejBfE0y8uF35fArCBeZjRlvJss=
github.com/prysmaticlabs/grpc-gateway/v2 v2.3.1-0.20210702154020-550e1cd83ec1/go.mod h1:IOyTYjcIO0rkmnGBfJTL0NJ11exy/Tc2QEuv7hCXp24=
github.com/prysmaticlabs/prombbolt v0.0.0-20210126082820-9b7adba6db7c h1:9PHRCuO/VN0s9k+RmLykho7AjDxblNYI5bYKed16NPU=

View File

@@ -98,7 +98,7 @@ type ExecutionBlock struct {
ReceiptsRoot []byte `protobuf:"bytes,8,opt,name=receipts_root,json=receiptsRoot,proto3" json:"receipts_root,omitempty"`
LogsBloom []byte `protobuf:"bytes,9,opt,name=logs_bloom,json=logsBloom,proto3" json:"logs_bloom,omitempty"`
Difficulty []byte `protobuf:"bytes,10,opt,name=difficulty,proto3" json:"difficulty,omitempty"`
TotalDifficulty []byte `protobuf:"bytes,11,opt,name=total_difficulty,json=totalDifficulty,proto3" json:"total_difficulty,omitempty"`
TotalDifficulty string `protobuf:"bytes,11,opt,name=total_difficulty,json=totalDifficulty,proto3" json:"total_difficulty,omitempty"`
GasLimit uint64 `protobuf:"varint,12,opt,name=gas_limit,json=gasLimit,proto3" json:"gas_limit,omitempty"`
GasUsed uint64 `protobuf:"varint,13,opt,name=gas_used,json=gasUsed,proto3" json:"gas_used,omitempty"`
BaseFeePerGas []byte `protobuf:"bytes,14,opt,name=base_fee_per_gas,json=baseFeePerGas,proto3" json:"base_fee_per_gas,omitempty"`
@@ -213,11 +213,11 @@ func (x *ExecutionBlock) GetDifficulty() []byte {
return nil
}
func (x *ExecutionBlock) GetTotalDifficulty() []byte {
func (x *ExecutionBlock) GetTotalDifficulty() string {
if x != nil {
return x.TotalDifficulty
}
return nil
return ""
}
func (x *ExecutionBlock) GetGasLimit() uint64 {
@@ -300,7 +300,7 @@ type ExecutionPayload struct {
StateRoot []byte `protobuf:"bytes,3,opt,name=state_root,json=stateRoot,proto3" json:"state_root,omitempty" ssz-size:"32"`
ReceiptsRoot []byte `protobuf:"bytes,4,opt,name=receipts_root,json=receiptsRoot,proto3" json:"receipts_root,omitempty" ssz-size:"32"`
LogsBloom []byte `protobuf:"bytes,5,opt,name=logs_bloom,json=logsBloom,proto3" json:"logs_bloom,omitempty" ssz-size:"256"`
Random []byte `protobuf:"bytes,6,opt,name=random,proto3" json:"random,omitempty" ssz-size:"32"`
PrevRandao []byte `protobuf:"bytes,6,opt,name=prev_randao,json=prevRandao,proto3" json:"prev_randao,omitempty" ssz-size:"32"`
BlockNumber uint64 `protobuf:"varint,7,opt,name=block_number,json=blockNumber,proto3" json:"block_number,omitempty"`
GasLimit uint64 `protobuf:"varint,8,opt,name=gas_limit,json=gasLimit,proto3" json:"gas_limit,omitempty"`
GasUsed uint64 `protobuf:"varint,9,opt,name=gas_used,json=gasUsed,proto3" json:"gas_used,omitempty"`
@@ -378,9 +378,9 @@ func (x *ExecutionPayload) GetLogsBloom() []byte {
return nil
}
func (x *ExecutionPayload) GetRandom() []byte {
func (x *ExecutionPayload) GetPrevRandao() []byte {
if x != nil {
return x.Random
return x.PrevRandao
}
return nil
}
@@ -510,7 +510,7 @@ type PayloadAttributes struct {
unknownFields protoimpl.UnknownFields
Timestamp uint64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
Random []byte `protobuf:"bytes,2,opt,name=random,proto3" json:"random,omitempty" ssz-size:"32"`
PrevRandao []byte `protobuf:"bytes,2,opt,name=prev_randao,json=prevRandao,proto3" json:"prev_randao,omitempty" ssz-size:"32"`
SuggestedFeeRecipient []byte `protobuf:"bytes,3,opt,name=suggested_fee_recipient,json=suggestedFeeRecipient,proto3" json:"suggested_fee_recipient,omitempty" ssz-size:"20"`
}
@@ -553,9 +553,9 @@ func (x *PayloadAttributes) GetTimestamp() uint64 {
return 0
}
func (x *PayloadAttributes) GetRandom() []byte {
func (x *PayloadAttributes) GetPrevRandao() []byte {
if x != nil {
return x.Random
return x.PrevRandao
}
return nil
}
@@ -723,7 +723,7 @@ var file_proto_engine_v1_execution_engine_proto_rawDesc = []byte{
0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x18, 0x0a,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79,
0x12, 0x29, 0x0a, 0x10, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63,
0x75, 0x6c, 0x74, 0x79, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x74, 0x6f, 0x74, 0x61,
0x75, 0x6c, 0x74, 0x79, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x74, 0x6f, 0x74, 0x61,
0x6c, 0x44, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x67,
0x61, 0x73, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08,
0x67, 0x61, 0x73, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x61, 0x73, 0x5f,
@@ -742,7 +742,7 @@ var file_proto_engine_v1_execution_engine_proto_rawDesc = []byte{
0x0a, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x14,
0x20, 0x03, 0x28, 0x0c, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x6e, 0x63, 0x6c, 0x65, 0x73, 0x18, 0x15, 0x20, 0x03,
0x28, 0x0c, 0x52, 0x06, 0x75, 0x6e, 0x63, 0x6c, 0x65, 0x73, 0x22, 0xbf, 0x04, 0x0a, 0x10, 0x45,
0x28, 0x0c, 0x52, 0x06, 0x75, 0x6e, 0x63, 0x6c, 0x65, 0x73, 0x22, 0xc8, 0x04, 0x0a, 0x10, 0x45,
0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12,
0x27, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x0a, 0x70, 0x61,
@@ -757,89 +757,90 @@ var file_proto_engine_v1_execution_engine_proto_rawDesc = []byte{
0x65, 0x69, 0x70, 0x74, 0x73, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x26, 0x0a, 0x0a, 0x6c, 0x6f, 0x67,
0x73, 0x5f, 0x62, 0x6c, 0x6f, 0x6f, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x07, 0x8a,
0xb5, 0x18, 0x03, 0x32, 0x35, 0x36, 0x52, 0x09, 0x6c, 0x6f, 0x67, 0x73, 0x42, 0x6c, 0x6f, 0x6f,
0x6d, 0x12, 0x1e, 0x0a, 0x06, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x18, 0x06, 0x20, 0x01, 0x28,
0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x06, 0x72, 0x61, 0x6e, 0x64, 0x6f,
0x6d, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65,
0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75,
0x6d, 0x62, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x67, 0x61, 0x73, 0x5f, 0x6c, 0x69, 0x6d, 0x69,
0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x67, 0x61, 0x73, 0x4c, 0x69, 0x6d, 0x69,
0x74, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x61, 0x73, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x18, 0x09, 0x20,
0x01, 0x28, 0x04, 0x52, 0x07, 0x67, 0x61, 0x73, 0x55, 0x73, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x09,
0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52,
0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x25, 0x0a, 0x0a, 0x65, 0x78,
0x74, 0x72, 0x61, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06,
0x92, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x09, 0x65, 0x78, 0x74, 0x72, 0x61, 0x44, 0x61, 0x74,
0x61, 0x12, 0x2f, 0x0a, 0x10, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x70, 0x65,
0x72, 0x5f, 0x67, 0x61, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18,
0x02, 0x33, 0x32, 0x52, 0x0d, 0x62, 0x61, 0x73, 0x65, 0x46, 0x65, 0x65, 0x50, 0x65, 0x72, 0x47,
0x61, 0x73, 0x12, 0x25, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68,
0x18, 0x0d, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x09,
0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x12, 0x41, 0x0a, 0x0c, 0x74, 0x72, 0x61,
0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x0c, 0x42,
0x1d, 0x8a, 0xb5, 0x18, 0x03, 0x3f, 0x2c, 0x3f, 0x92, 0xb5, 0x18, 0x12, 0x31, 0x30, 0x34, 0x38,
0x35, 0x37, 0x36, 0x2c, 0x31, 0x30, 0x37, 0x33, 0x37, 0x34, 0x31, 0x38, 0x32, 0x34, 0x52, 0x0c,
0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xb9, 0x01, 0x0a,
0x17, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3a, 0x0a, 0x19, 0x74, 0x65, 0x72, 0x6d,
0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x64, 0x69, 0x66, 0x66, 0x69,
0x63, 0x75, 0x6c, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x17, 0x74, 0x65, 0x72,
0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x69, 0x63,
0x75, 0x6c, 0x74, 0x79, 0x12, 0x2e, 0x0a, 0x13, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c,
0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28,
0x0c, 0x52, 0x11, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x42, 0x6c, 0x6f, 0x63, 0x6b,
0x48, 0x61, 0x73, 0x68, 0x12, 0x32, 0x0a, 0x15, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c,
0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, 0x20,
0x01, 0x28, 0x0c, 0x52, 0x13, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x42, 0x6c, 0x6f,
0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x91, 0x01, 0x0a, 0x11, 0x50, 0x61, 0x79,
0x6c, 0x6f, 0x61, 0x64, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x1c,
0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28,
0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1e, 0x0a, 0x06,
0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5,
0x18, 0x02, 0x33, 0x32, 0x52, 0x06, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x12, 0x3e, 0x0a, 0x17,
0x73, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x72, 0x65,
0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a,
0xb5, 0x18, 0x02, 0x32, 0x30, 0x52, 0x15, 0x73, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x65, 0x64,
0x46, 0x65, 0x65, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x22, 0xae, 0x02, 0x0a,
0x0d, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x40,
0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x28,
0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65,
0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75,
0x73, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
0x12, 0x32, 0x0a, 0x11, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x69, 0x64,
0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18,
0x02, 0x33, 0x32, 0x52, 0x0f, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x69, 0x64,
0x48, 0x61, 0x73, 0x68, 0x12, 0x29, 0x0a, 0x10, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f,
0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x22,
0x7c, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b,
0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10,
0x01, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x02, 0x12, 0x0b,
0x0a, 0x07, 0x53, 0x59, 0x4e, 0x43, 0x49, 0x4e, 0x47, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x41,
0x43, 0x43, 0x45, 0x50, 0x54, 0x45, 0x44, 0x10, 0x04, 0x12, 0x16, 0x0a, 0x12, 0x49, 0x4e, 0x56,
0x41, 0x4c, 0x49, 0x44, 0x5f, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x5f, 0x48, 0x41, 0x53, 0x48, 0x10,
0x05, 0x12, 0x1a, 0x0a, 0x16, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x54, 0x45, 0x52,
0x4d, 0x49, 0x4e, 0x41, 0x4c, 0x5f, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x06, 0x22, 0xab, 0x01,
0x0a, 0x0f, 0x46, 0x6f, 0x72, 0x6b, 0x63, 0x68, 0x6f, 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74,
0x65, 0x12, 0x2e, 0x0a, 0x0f, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f,
0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02,
0x33, 0x32, 0x52, 0x0d, 0x68, 0x65, 0x61, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73,
0x68, 0x12, 0x2e, 0x0a, 0x0f, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f,
0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02,
0x33, 0x32, 0x52, 0x0d, 0x73, 0x61, 0x66, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73,
0x68, 0x12, 0x38, 0x0a, 0x14, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x62,
0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x42,
0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x12, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a,
0x65, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x42, 0x93, 0x01, 0x0a, 0x16,
0x6f, 0x72, 0x67, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x6e, 0x67,
0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x42, 0x14, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f,
0x6e, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x37,
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d,
0x61, 0x74, 0x69, 0x63, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x65,
0x6e, 0x67, 0x69, 0x6e, 0x65, 0x76, 0x31, 0xaa, 0x02, 0x12, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65,
0x75, 0x6d, 0x2e, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x12, 0x45,
0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x5c, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x5c, 0x76,
0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x6d, 0x12, 0x27, 0x0a, 0x0b, 0x70, 0x72, 0x65, 0x76, 0x5f, 0x72, 0x61, 0x6e, 0x64, 0x61, 0x6f,
0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x0a,
0x70, 0x72, 0x65, 0x76, 0x52, 0x61, 0x6e, 0x64, 0x61, 0x6f, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x6c,
0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04,
0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1b, 0x0a,
0x09, 0x67, 0x61, 0x73, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04,
0x52, 0x08, 0x67, 0x61, 0x73, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x61,
0x73, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x67, 0x61,
0x73, 0x55, 0x73, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
0x6d, 0x70, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74,
0x61, 0x6d, 0x70, 0x12, 0x25, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x72, 0x61, 0x5f, 0x64, 0x61, 0x74,
0x61, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x92, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52,
0x09, 0x65, 0x78, 0x74, 0x72, 0x61, 0x44, 0x61, 0x74, 0x61, 0x12, 0x2f, 0x0a, 0x10, 0x62, 0x61,
0x73, 0x65, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x67, 0x61, 0x73, 0x18, 0x0c,
0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x0d, 0x62, 0x61,
0x73, 0x65, 0x46, 0x65, 0x65, 0x50, 0x65, 0x72, 0x47, 0x61, 0x73, 0x12, 0x25, 0x0a, 0x0a, 0x62,
0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0c, 0x42,
0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61,
0x73, 0x68, 0x12, 0x41, 0x0a, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x0c, 0x42, 0x1d, 0x8a, 0xb5, 0x18, 0x03, 0x3f, 0x2c,
0x3f, 0x92, 0xb5, 0x18, 0x12, 0x31, 0x30, 0x34, 0x38, 0x35, 0x37, 0x36, 0x2c, 0x31, 0x30, 0x37,
0x33, 0x37, 0x34, 0x31, 0x38, 0x32, 0x34, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xb9, 0x01, 0x0a, 0x17, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69,
0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x12, 0x3a, 0x0a, 0x19, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x74, 0x6f,
0x74, 0x61, 0x6c, 0x5f, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x17, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x54, 0x6f,
0x74, 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x12, 0x2e, 0x0a,
0x13, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f,
0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x11, 0x74, 0x65, 0x72, 0x6d,
0x69, 0x6e, 0x61, 0x6c, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x12, 0x32, 0x0a,
0x15, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f,
0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x13, 0x74, 0x65,
0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65,
0x72, 0x22, 0x9a, 0x01, 0x0a, 0x11, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x41, 0x74, 0x74,
0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73,
0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65,
0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x27, 0x0a, 0x0b, 0x70, 0x72, 0x65, 0x76, 0x5f, 0x72, 0x61,
0x6e, 0x64, 0x61, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02,
0x33, 0x32, 0x52, 0x0a, 0x70, 0x72, 0x65, 0x76, 0x52, 0x61, 0x6e, 0x64, 0x61, 0x6f, 0x12, 0x3e,
0x0a, 0x17, 0x73, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x66, 0x65, 0x65, 0x5f,
0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x42,
0x06, 0x8a, 0xb5, 0x18, 0x02, 0x32, 0x30, 0x52, 0x15, 0x73, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74,
0x65, 0x64, 0x46, 0x65, 0x65, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x22, 0xae,
0x02, 0x0a, 0x0d, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
0x12, 0x40, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e,
0x32, 0x28, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x6e, 0x67, 0x69,
0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x74, 0x61,
0x74, 0x75, 0x73, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74,
0x75, 0x73, 0x12, 0x32, 0x0a, 0x11, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x76, 0x61, 0x6c,
0x69, 0x64, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a,
0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x0f, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x56, 0x61, 0x6c,
0x69, 0x64, 0x48, 0x61, 0x73, 0x68, 0x12, 0x29, 0x0a, 0x10, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
0x52, 0x0f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f,
0x72, 0x22, 0x7c, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55,
0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x56, 0x41, 0x4c, 0x49,
0x44, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x02,
0x12, 0x0b, 0x0a, 0x07, 0x53, 0x59, 0x4e, 0x43, 0x49, 0x4e, 0x47, 0x10, 0x03, 0x12, 0x0c, 0x0a,
0x08, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x45, 0x44, 0x10, 0x04, 0x12, 0x16, 0x0a, 0x12, 0x49,
0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x5f, 0x48, 0x41, 0x53,
0x48, 0x10, 0x05, 0x12, 0x1a, 0x0a, 0x16, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x54,
0x45, 0x52, 0x4d, 0x49, 0x4e, 0x41, 0x4c, 0x5f, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x06, 0x22,
0xab, 0x01, 0x0a, 0x0f, 0x46, 0x6f, 0x72, 0x6b, 0x63, 0x68, 0x6f, 0x69, 0x63, 0x65, 0x53, 0x74,
0x61, 0x74, 0x65, 0x12, 0x2e, 0x0a, 0x0f, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x62, 0x6c, 0x6f, 0x63,
0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5,
0x18, 0x02, 0x33, 0x32, 0x52, 0x0d, 0x68, 0x65, 0x61, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48,
0x61, 0x73, 0x68, 0x12, 0x2e, 0x0a, 0x0f, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x62, 0x6c, 0x6f, 0x63,
0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5,
0x18, 0x02, 0x33, 0x32, 0x52, 0x0d, 0x73, 0x61, 0x66, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48,
0x61, 0x73, 0x68, 0x12, 0x38, 0x0a, 0x14, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64,
0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28,
0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x12, 0x66, 0x69, 0x6e, 0x61, 0x6c,
0x69, 0x7a, 0x65, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x42, 0x93, 0x01,
0x0a, 0x16, 0x6f, 0x72, 0x67, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65,
0x6e, 0x67, 0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x42, 0x14, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74,
0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01,
0x5a, 0x37, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x79,
0x73, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d,
0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x2f, 0x76, 0x31,
0x3b, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x76, 0x31, 0xaa, 0x02, 0x12, 0x45, 0x74, 0x68, 0x65,
0x72, 0x65, 0x75, 0x6d, 0x2e, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x2e, 0x56, 0x31, 0xca, 0x02,
0x12, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x5c, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65,
0x5c, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (

View File

@@ -35,10 +35,10 @@ message ExecutionBlock {
bytes receipts_root = 8;
bytes logs_bloom = 9;
bytes difficulty = 10;
bytes total_difficulty = 11;
string total_difficulty = 11;
uint64 gas_limit = 12;
uint64 gas_used = 13;
bytes base_fee_per_gas = 14;
bytes base_fee_per_gas = 14;
bytes size = 15;
uint64 timestamp = 16;
bytes extra_data = 17;
@@ -54,7 +54,7 @@ message ExecutionPayload {
bytes state_root = 3 [(ethereum.eth.ext.ssz_size) = "32"];
bytes receipts_root = 4 [(ethereum.eth.ext.ssz_size) = "32"];
bytes logs_bloom = 5 [(ethereum.eth.ext.ssz_size) = "256"];
bytes random = 6 [(ethereum.eth.ext.ssz_size) = "32"];
bytes prev_randao = 6 [(ethereum.eth.ext.ssz_size) = "32"];
uint64 block_number = 7;
uint64 gas_limit = 8;
uint64 gas_used = 9;
@@ -73,7 +73,7 @@ message TransitionConfiguration {
message PayloadAttributes {
uint64 timestamp = 1;
bytes random = 2 [(ethereum.eth.ext.ssz_size) = "32"];
bytes prev_randao = 2 [(ethereum.eth.ext.ssz_size) = "32"];
bytes suggested_fee_recipient = 3 [(ethereum.eth.ext.ssz_size) = "20"];
}

View File

@@ -1,5 +1,5 @@
// Code generated by fastssz. DO NOT EDIT.
// Hash: 1786ca114ebca73885d43bbe86c5e33b0a4c2f43f8289530ed8036b9df46cb3a
// Hash: 48b23fe0bad1a25d6921cb1c508752fcd4021e062886bb513674206b91d2bd83
package enginev1
import (
@@ -51,12 +51,12 @@ func (e *ExecutionPayload) MarshalSSZTo(buf []byte) (dst []byte, err error) {
}
dst = append(dst, e.LogsBloom...)
// Field (5) 'Random'
if len(e.Random) != 32 {
// Field (5) 'PrevRandao'
if len(e.PrevRandao) != 32 {
err = ssz.ErrBytesLength
return
}
dst = append(dst, e.Random...)
dst = append(dst, e.PrevRandao...)
// Field (6) 'BlockNumber'
dst = ssz.MarshalUint64(dst, e.BlockNumber)
@@ -166,11 +166,11 @@ func (e *ExecutionPayload) UnmarshalSSZ(buf []byte) error {
}
e.LogsBloom = append(e.LogsBloom, buf[116:372]...)
// Field (5) 'Random'
if cap(e.Random) == 0 {
e.Random = make([]byte, 0, len(buf[372:404]))
// Field (5) 'PrevRandao'
if cap(e.PrevRandao) == 0 {
e.PrevRandao = make([]byte, 0, len(buf[372:404]))
}
e.Random = append(e.Random, buf[372:404]...)
e.PrevRandao = append(e.PrevRandao, buf[372:404]...)
// Field (6) 'BlockNumber'
e.BlockNumber = ssz.UnmarshallUint64(buf[404:412])
@@ -307,12 +307,12 @@ func (e *ExecutionPayload) HashTreeRootWith(hh *ssz.Hasher) (err error) {
}
hh.PutBytes(e.LogsBloom)
// Field (5) 'Random'
if len(e.Random) != 32 {
// Field (5) 'PrevRandao'
if len(e.PrevRandao) != 32 {
err = ssz.ErrBytesLength
return
}
hh.PutBytes(e.Random)
hh.PutBytes(e.PrevRandao)
// Field (6) 'BlockNumber'
hh.PutUint64(e.BlockNumber)

View File

@@ -71,9 +71,6 @@ func (e *ExecutionBlock) MarshalJSON() ([]byte, error) {
diff := new(big.Int).SetBytes(e.Difficulty)
diffHex := hexutil.EncodeBig(diff)
totalDiff := new(big.Int).SetBytes(e.TotalDifficulty)
totalDiffHex := hexutil.EncodeBig(totalDiff)
size := new(big.Int).SetBytes(e.Size)
sizeHex := hexutil.EncodeBig(size)
@@ -90,7 +87,7 @@ func (e *ExecutionBlock) MarshalJSON() ([]byte, error) {
ReceiptsRoot: e.ReceiptsRoot,
LogsBloom: e.LogsBloom,
Difficulty: diffHex,
TotalDifficulty: totalDiffHex,
TotalDifficulty: e.TotalDifficulty,
GasLimit: hexutil.Uint64(e.GasLimit),
GasUsed: hexutil.Uint64(e.GasUsed),
Timestamp: hexutil.Uint64(e.Timestamp),
@@ -130,11 +127,7 @@ func (e *ExecutionBlock) UnmarshalJSON(enc []byte) error {
return err
}
e.Difficulty = diff.Bytes()
totalDiff, err := hexutil.DecodeBig(dec.TotalDifficulty)
if err != nil {
return err
}
e.TotalDifficulty = totalDiff.Bytes()
e.TotalDifficulty = dec.TotalDifficulty
e.GasLimit = uint64(dec.GasLimit)
e.GasUsed = uint64(dec.GasUsed)
e.Timestamp = uint64(dec.Timestamp)
@@ -170,7 +163,7 @@ type executionPayloadJSON struct {
StateRoot hexutil.Bytes `json:"stateRoot"`
ReceiptsRoot hexutil.Bytes `json:"receiptsRoot"`
LogsBloom hexutil.Bytes `json:"logsBloom"`
Random hexutil.Bytes `json:"random"`
PrevRandao hexutil.Bytes `json:"prevRandao"`
BlockNumber hexutil.Uint64 `json:"blockNumber"`
GasLimit hexutil.Uint64 `json:"gasLimit"`
GasUsed hexutil.Uint64 `json:"gasUsed"`
@@ -195,7 +188,7 @@ func (e *ExecutionPayload) MarshalJSON() ([]byte, error) {
StateRoot: e.StateRoot,
ReceiptsRoot: e.ReceiptsRoot,
LogsBloom: e.LogsBloom,
Random: e.Random,
PrevRandao: e.PrevRandao,
BlockNumber: hexutil.Uint64(e.BlockNumber),
GasLimit: hexutil.Uint64(e.GasLimit),
GasUsed: hexutil.Uint64(e.GasUsed),
@@ -219,7 +212,7 @@ func (e *ExecutionPayload) UnmarshalJSON(enc []byte) error {
e.StateRoot = bytesutil.PadTo(dec.StateRoot, fieldparams.RootLength)
e.ReceiptsRoot = bytesutil.PadTo(dec.ReceiptsRoot, fieldparams.RootLength)
e.LogsBloom = bytesutil.PadTo(dec.LogsBloom, fieldparams.LogsBloomLength)
e.Random = bytesutil.PadTo(dec.Random, fieldparams.RootLength)
e.PrevRandao = bytesutil.PadTo(dec.PrevRandao, fieldparams.RootLength)
e.BlockNumber = uint64(dec.BlockNumber)
e.GasLimit = uint64(dec.GasLimit)
e.GasUsed = uint64(dec.GasUsed)
@@ -241,7 +234,7 @@ func (e *ExecutionPayload) UnmarshalJSON(enc []byte) error {
type payloadAttributesJSON struct {
Timestamp hexutil.Uint64 `json:"timestamp"`
Random hexutil.Bytes `json:"random"`
PrevRandao hexutil.Bytes `json:"prevRandao"`
SuggestedFeeRecipient hexutil.Bytes `json:"suggestedFeeRecipient"`
}
@@ -249,7 +242,7 @@ type payloadAttributesJSON struct {
func (p *PayloadAttributes) MarshalJSON() ([]byte, error) {
return json.Marshal(payloadAttributesJSON{
Timestamp: hexutil.Uint64(p.Timestamp),
Random: p.Random,
PrevRandao: p.PrevRandao,
SuggestedFeeRecipient: p.SuggestedFeeRecipient,
})
}
@@ -262,7 +255,7 @@ func (p *PayloadAttributes) UnmarshalJSON(enc []byte) error {
}
*p = PayloadAttributes{}
p.Timestamp = uint64(dec.Timestamp)
p.Random = dec.Random
p.PrevRandao = dec.PrevRandao
p.SuggestedFeeRecipient = dec.SuggestedFeeRecipient
return nil
}

View File

@@ -18,7 +18,7 @@ func TestJsonMarshalUnmarshal(t *testing.T) {
feeRecipient := bytesutil.PadTo([]byte("feeRecipient"), fieldparams.FeeRecipientLength)
jsonPayload := &enginev1.PayloadAttributes{
Timestamp: 1,
Random: random,
PrevRandao: random,
SuggestedFeeRecipient: feeRecipient,
}
enc, err := json.Marshal(jsonPayload)
@@ -26,7 +26,7 @@ func TestJsonMarshalUnmarshal(t *testing.T) {
payloadPb := &enginev1.PayloadAttributes{}
require.NoError(t, json.Unmarshal(enc, payloadPb))
require.DeepEqual(t, uint64(1), payloadPb.Timestamp)
require.DeepEqual(t, random, payloadPb.Random)
require.DeepEqual(t, random, payloadPb.PrevRandao)
require.DeepEqual(t, feeRecipient, payloadPb.SuggestedFeeRecipient)
})
t.Run("payload status", func(t *testing.T) {
@@ -79,7 +79,6 @@ func TestJsonMarshalUnmarshal(t *testing.T) {
})
t.Run("execution payload", func(t *testing.T) {
baseFeePerGas := big.NewInt(6)
baseFeePerGasBytes := bytesutil.ReverseByteOrder(baseFeePerGas.Bytes())
parentHash := bytesutil.PadTo([]byte("parent"), fieldparams.RootLength)
feeRecipient := bytesutil.PadTo([]byte("feeRecipient"), fieldparams.FeeRecipientLength)
stateRoot := bytesutil.PadTo([]byte("stateRoot"), fieldparams.RootLength)
@@ -94,13 +93,13 @@ func TestJsonMarshalUnmarshal(t *testing.T) {
StateRoot: stateRoot,
ReceiptsRoot: receiptsRoot,
LogsBloom: logsBloom,
Random: random,
PrevRandao: random,
BlockNumber: 1,
GasLimit: 2,
GasUsed: 3,
Timestamp: 4,
ExtraData: extra,
BaseFeePerGas: baseFeePerGasBytes,
BaseFeePerGas: baseFeePerGas.Bytes(),
BlockHash: hash,
Transactions: [][]byte{[]byte("hi")},
}
@@ -113,7 +112,7 @@ func TestJsonMarshalUnmarshal(t *testing.T) {
require.DeepEqual(t, stateRoot, payloadPb.StateRoot)
require.DeepEqual(t, receiptsRoot, payloadPb.ReceiptsRoot)
require.DeepEqual(t, logsBloom, payloadPb.LogsBloom)
require.DeepEqual(t, random, payloadPb.Random)
require.DeepEqual(t, random, payloadPb.PrevRandao)
require.DeepEqual(t, uint64(1), payloadPb.BlockNumber)
require.DeepEqual(t, uint64(2), payloadPb.GasLimit)
require.DeepEqual(t, uint64(3), payloadPb.GasUsed)
@@ -135,7 +134,7 @@ func TestJsonMarshalUnmarshal(t *testing.T) {
ReceiptsRoot: []byte("receiptsRoot"),
LogsBloom: []byte("logsBloom"),
Difficulty: []byte("1"),
TotalDifficulty: []byte("2"),
TotalDifficulty: "2",
GasLimit: 3,
GasUsed: 4,
Timestamp: 5,
@@ -161,7 +160,7 @@ func TestJsonMarshalUnmarshal(t *testing.T) {
require.DeepEqual(t, []byte("receiptsRoot"), payloadPb.ReceiptsRoot)
require.DeepEqual(t, []byte("logsBloom"), payloadPb.LogsBloom)
require.DeepEqual(t, []byte("1"), payloadPb.Difficulty)
require.DeepEqual(t, []byte("2"), payloadPb.TotalDifficulty)
require.DeepEqual(t, "2", payloadPb.TotalDifficulty)
require.DeepEqual(t, uint64(3), payloadPb.GasLimit)
require.DeepEqual(t, uint64(4), payloadPb.GasUsed)
require.DeepEqual(t, uint64(5), payloadPb.Timestamp)

View File

@@ -28,7 +28,7 @@ go_test(
deps = [
"//config/params:go_default_library",
"//crypto/bls:go_default_library",
"//encoding/ssz:go_default_library",
"//encoding/ssz/equality:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/attestation/aggregation:go_default_library",
"//proto/prysm/v1alpha1/attestation/aggregation/testing:go_default_library",

View File

@@ -8,7 +8,7 @@ import (
"github.com/prysmaticlabs/go-bitfield"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/encoding/ssz"
"github.com/prysmaticlabs/prysm/encoding/ssz/equality"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/attestation/aggregation"
aggtesting "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/attestation/aggregation/testing"
@@ -48,7 +48,7 @@ func TestAggregateAttestations_AggregatePair(t *testing.T) {
for _, tt := range tests {
got, err := AggregatePair(tt.a1, tt.a2)
require.NoError(t, err)
require.Equal(t, true, ssz.DeepEqual(got, tt.want))
require.Equal(t, true, equality.DeepEqual(got, tt.want))
}
}

View File

@@ -1317,7 +1317,7 @@ type ExecutionPayloadHeader struct {
StateRoot []byte `protobuf:"bytes,3,opt,name=state_root,json=stateRoot,proto3" json:"state_root,omitempty" ssz-size:"32"`
ReceiptRoot []byte `protobuf:"bytes,4,opt,name=receipt_root,json=receiptRoot,proto3" json:"receipt_root,omitempty" ssz-size:"32"`
LogsBloom []byte `protobuf:"bytes,5,opt,name=logs_bloom,json=logsBloom,proto3" json:"logs_bloom,omitempty" ssz-size:"256"`
Random []byte `protobuf:"bytes,6,opt,name=random,proto3" json:"random,omitempty" ssz-size:"32"`
PrevRandao []byte `protobuf:"bytes,6,opt,name=prev_randao,json=prevRandao,proto3" json:"prev_randao,omitempty" ssz-size:"32"`
BlockNumber uint64 `protobuf:"varint,7,opt,name=block_number,json=blockNumber,proto3" json:"block_number,omitempty"`
GasLimit uint64 `protobuf:"varint,8,opt,name=gas_limit,json=gasLimit,proto3" json:"gas_limit,omitempty"`
GasUsed uint64 `protobuf:"varint,9,opt,name=gas_used,json=gasUsed,proto3" json:"gas_used,omitempty"`
@@ -1395,9 +1395,9 @@ func (x *ExecutionPayloadHeader) GetLogsBloom() []byte {
return nil
}
func (x *ExecutionPayloadHeader) GetRandom() []byte {
func (x *ExecutionPayloadHeader) GetPrevRandao() []byte {
if x != nil {
return x.Random
return x.PrevRandao
}
return nil
}
@@ -1953,7 +1953,7 @@ var file_proto_prysm_v1alpha1_beacon_state_proto_rawDesc = []byte{
0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74,
0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72,
0x52, 0x1c, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f,
0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x22, 0xb5,
0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x22, 0xbe,
0x04, 0x0a, 0x16, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c,
0x6f, 0x61, 0x64, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x27, 0x0a, 0x0b, 0x70, 0x61, 0x72,
0x65, 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06,
@@ -1968,47 +1968,48 @@ var file_proto_prysm_v1alpha1_beacon_state_proto_rawDesc = []byte{
0x18, 0x02, 0x33, 0x32, 0x52, 0x0b, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x52, 0x6f, 0x6f,
0x74, 0x12, 0x26, 0x0a, 0x0a, 0x6c, 0x6f, 0x67, 0x73, 0x5f, 0x62, 0x6c, 0x6f, 0x6f, 0x6d, 0x18,
0x05, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x07, 0x8a, 0xb5, 0x18, 0x03, 0x32, 0x35, 0x36, 0x52, 0x09,
0x6c, 0x6f, 0x67, 0x73, 0x42, 0x6c, 0x6f, 0x6f, 0x6d, 0x12, 0x1e, 0x0a, 0x06, 0x72, 0x61, 0x6e,
0x64, 0x6f, 0x6d, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33,
0x32, 0x52, 0x06, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x6c, 0x6f,
0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52,
0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09,
0x67, 0x61, 0x73, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52,
0x08, 0x67, 0x61, 0x73, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x61, 0x73,
0x5f, 0x75, 0x73, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x67, 0x61, 0x73,
0x55, 0x73, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
0x70, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
0x6d, 0x70, 0x12, 0x25, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x72, 0x61, 0x5f, 0x64, 0x61, 0x74, 0x61,
0x18, 0x0b, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x92, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x09,
0x65, 0x78, 0x74, 0x72, 0x61, 0x44, 0x61, 0x74, 0x61, 0x12, 0x2f, 0x0a, 0x10, 0x62, 0x61, 0x73,
0x65, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x67, 0x61, 0x73, 0x18, 0x0c, 0x20,
0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x0d, 0x62, 0x61, 0x73,
0x65, 0x46, 0x65, 0x65, 0x50, 0x65, 0x72, 0x47, 0x61, 0x73, 0x12, 0x25, 0x0a, 0x0a, 0x62, 0x6c,
0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06,
0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73,
0x68, 0x12, 0x33, 0x0a, 0x11, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e,
0x73, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5,
0x18, 0x02, 0x33, 0x32, 0x52, 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x73, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x8d, 0x01, 0x0a, 0x08, 0x50, 0x6f, 0x77, 0x42, 0x6c,
0x6f, 0x63, 0x6b, 0x12, 0x25, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x61, 0x73,
0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52,
0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x12, 0x27, 0x0a, 0x0b, 0x70, 0x61,
0x72, 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42,
0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48,
0x61, 0x73, 0x68, 0x12, 0x31, 0x0a, 0x10, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x64, 0x69, 0x66,
0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a,
0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x0f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66,
0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x42, 0x98, 0x01, 0x0a, 0x19, 0x6f, 0x72, 0x67, 0x2e, 0x65,
0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c,
0x70, 0x68, 0x61, 0x31, 0x42, 0x10, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74,
0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x37, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x6c, 0x61,
0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70,
0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x3b, 0x65, 0x74,
0x68, 0xaa, 0x02, 0x15, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x45, 0x74, 0x68,
0x2e, 0x56, 0x31, 0x41, 0x6c, 0x70, 0x68, 0x61, 0x31, 0xca, 0x02, 0x15, 0x45, 0x74, 0x68, 0x65,
0x72, 0x65, 0x75, 0x6d, 0x5c, 0x45, 0x74, 0x68, 0x5c, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61,
0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x6c, 0x6f, 0x67, 0x73, 0x42, 0x6c, 0x6f, 0x6f, 0x6d, 0x12, 0x27, 0x0a, 0x0b, 0x70, 0x72, 0x65,
0x76, 0x5f, 0x72, 0x61, 0x6e, 0x64, 0x61, 0x6f, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06,
0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x0a, 0x70, 0x72, 0x65, 0x76, 0x52, 0x61, 0x6e, 0x64,
0x61, 0x6f, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62,
0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e,
0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x67, 0x61, 0x73, 0x5f, 0x6c, 0x69, 0x6d,
0x69, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x67, 0x61, 0x73, 0x4c, 0x69, 0x6d,
0x69, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x61, 0x73, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x18, 0x09,
0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x67, 0x61, 0x73, 0x55, 0x73, 0x65, 0x64, 0x12, 0x1c, 0x0a,
0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04,
0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x25, 0x0a, 0x0a, 0x65,
0x78, 0x74, 0x72, 0x61, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0c, 0x42,
0x06, 0x92, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x09, 0x65, 0x78, 0x74, 0x72, 0x61, 0x44, 0x61,
0x74, 0x61, 0x12, 0x2f, 0x0a, 0x10, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x70,
0x65, 0x72, 0x5f, 0x67, 0x61, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5,
0x18, 0x02, 0x33, 0x32, 0x52, 0x0d, 0x62, 0x61, 0x73, 0x65, 0x46, 0x65, 0x65, 0x50, 0x65, 0x72,
0x47, 0x61, 0x73, 0x12, 0x25, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x61, 0x73,
0x68, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52,
0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x12, 0x33, 0x0a, 0x11, 0x74, 0x72,
0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18,
0x0e, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x10, 0x74,
0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x6f, 0x6f, 0x74, 0x22,
0x8d, 0x01, 0x0a, 0x08, 0x50, 0x6f, 0x77, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x25, 0x0a, 0x0a,
0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c,
0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48,
0x61, 0x73, 0x68, 0x12, 0x27, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x61,
0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32,
0x52, 0x0a, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x31, 0x0a, 0x10,
0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79,
0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x0f,
0x74, 0x6f, 0x74, 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x42,
0x98, 0x01, 0x0a, 0x19, 0x6f, 0x72, 0x67, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d,
0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x42, 0x10, 0x42,
0x65, 0x61, 0x63, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50,
0x01, 0x5a, 0x37, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72,
0x79, 0x73, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73,
0x6d, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x31,
0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x3b, 0x65, 0x74, 0x68, 0xaa, 0x02, 0x15, 0x45, 0x74, 0x68,
0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x45, 0x74, 0x68, 0x2e, 0x56, 0x31, 0x41, 0x6c, 0x70, 0x68,
0x61, 0x31, 0xca, 0x02, 0x15, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x5c, 0x45, 0x74,
0x68, 0x5c, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
}
var (

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