diff --git a/api/gateway/gateway.go b/api/gateway/gateway.go index efe1c9d9680e..0bb0a27cc0a7 100644 --- a/api/gateway/gateway.go +++ b/api/gateway/gateway.go @@ -70,15 +70,16 @@ type Gateway struct { func New(ctx context.Context, opts ...Option) (*Gateway, error) { g := &Gateway{ ctx: ctx, - cfg: &config{ - router: mux.NewRouter(), - }, + cfg: &config{}, } for _, opt := range opts { if err := opt(g); err != nil { return nil, err } } + if g.cfg.router == nil { + g.cfg.router = mux.NewRouter() + } return g, nil } diff --git a/api/gateway/options.go b/api/gateway/options.go index cc5e5a8842b3..337aa60ccb7b 100644 --- a/api/gateway/options.go +++ b/api/gateway/options.go @@ -10,11 +10,6 @@ import ( type Option func(g *Gateway) error -func (g *Gateway) SetRouter(r *mux.Router) *Gateway { - g.cfg.router = r - return g -} - func WithPbHandlers(handlers []*PbMux) Option { return func(g *Gateway) error { g.cfg.pbHandlers = handlers diff --git a/beacon-chain/node/BUILD.bazel b/beacon-chain/node/BUILD.bazel index 00016e0dcda4..4e55b377ef31 100644 --- a/beacon-chain/node/BUILD.bazel +++ b/beacon-chain/node/BUILD.bazel @@ -61,6 +61,7 @@ go_library( "//runtime/prereqs:go_default_library", "//runtime/version:go_default_library", "@com_github_ethereum_go_ethereum//common:go_default_library", + "@com_github_gorilla_mux//:go_default_library", "@com_github_pkg_errors//:go_default_library", "@com_github_prometheus_client_golang//prometheus:go_default_library", "@com_github_prysmaticlabs_fastssz//:go_default_library", diff --git a/beacon-chain/node/node.go b/beacon-chain/node/node.go index c43986013b0f..f360a87677a4 100644 --- a/beacon-chain/node/node.go +++ b/beacon-chain/node/node.go @@ -15,6 +15,7 @@ import ( "syscall" "github.com/ethereum/go-ethereum/common" + "github.com/gorilla/mux" "github.com/pkg/errors" apigateway "github.com/prysmaticlabs/prysm/v4/api/gateway" "github.com/prysmaticlabs/prysm/v4/async/event" @@ -253,12 +254,13 @@ func New(cliCtx *cli.Context, opts ...Option) (*BeaconNode, error) { } log.Debugln("Registering RPC Service") - if err := beacon.registerRPCService(); err != nil { + router := mux.NewRouter() + if err := beacon.registerRPCService(router); err != nil { return nil, err } log.Debugln("Registering GRPC Gateway Service") - if err := beacon.registerGRPCGateway(); err != nil { + if err := beacon.registerGRPCGateway(router); err != nil { return nil, err } @@ -734,7 +736,7 @@ func (b *BeaconNode) registerSlasherService() error { return b.services.RegisterService(slasherSrv) } -func (b *BeaconNode) registerRPCService() error { +func (b *BeaconNode) registerRPCService(router *mux.Router) error { var chainService *blockchain.Service if err := b.services.FetchService(&chainService); err != nil { return err @@ -830,6 +832,7 @@ func (b *BeaconNode) registerRPCService() error { MaxMsgSize: maxMsgSize, ProposerIdsCache: b.proposerIdsCache, BlockBuilder: b.fetchBuilderService(), + Router: router, }) return b.services.RegisterService(rpcService) @@ -858,7 +861,7 @@ func (b *BeaconNode) registerPrometheusService(_ *cli.Context) error { return b.services.RegisterService(service) } -func (b *BeaconNode) registerGRPCGateway() error { +func (b *BeaconNode) registerGRPCGateway(router *mux.Router) error { if b.cliCtx.Bool(flags.DisableGRPCGateway.Name) { return nil } @@ -884,6 +887,7 @@ func (b *BeaconNode) registerGRPCGateway() error { } opts := []apigateway.Option{ + apigateway.WithRouter(router), apigateway.WithGatewayAddr(gatewayAddress), apigateway.WithRemoteAddr(selfAddress), apigateway.WithPbHandlers(muxs), diff --git a/beacon-chain/rpc/BUILD.bazel b/beacon-chain/rpc/BUILD.bazel index 0f0d79f4e2f5..ae5473e36026 100644 --- a/beacon-chain/rpc/BUILD.bazel +++ b/beacon-chain/rpc/BUILD.bazel @@ -28,12 +28,13 @@ go_library( "//beacon-chain/rpc/eth/debug:go_default_library", "//beacon-chain/rpc/eth/events:go_default_library", "//beacon-chain/rpc/eth/node:go_default_library", + "//beacon-chain/rpc/eth/rewards:go_default_library", "//beacon-chain/rpc/eth/validator:go_default_library", + "//beacon-chain/rpc/lookup:go_default_library", "//beacon-chain/rpc/prysm/v1alpha1/beacon:go_default_library", "//beacon-chain/rpc/prysm/v1alpha1/debug:go_default_library", "//beacon-chain/rpc/prysm/v1alpha1/node:go_default_library", "//beacon-chain/rpc/prysm/v1alpha1/validator:go_default_library", - "//beacon-chain/rpc/statefetcher:go_default_library", "//beacon-chain/slasher:go_default_library", "//beacon-chain/state/stategen:go_default_library", "//beacon-chain/sync:go_default_library", @@ -43,6 +44,7 @@ go_library( "//monitoring/tracing:go_default_library", "//proto/eth/service:go_default_library", "//proto/prysm/v1alpha1:go_default_library", + "@com_github_gorilla_mux//:go_default_library", "@com_github_grpc_ecosystem_go_grpc_middleware//:go_default_library", "@com_github_grpc_ecosystem_go_grpc_middleware//recovery:go_default_library", "@com_github_grpc_ecosystem_go_grpc_middleware//tracing/opentracing:go_default_library", @@ -68,6 +70,7 @@ go_test( "//beacon-chain/sync/initial-sync/testing:go_default_library", "//testing/assert:go_default_library", "//testing/require:go_default_library", + "@com_github_gorilla_mux//:go_default_library", "@com_github_sirupsen_logrus//:go_default_library", "@com_github_sirupsen_logrus//hooks/test:go_default_library", ], diff --git a/beacon-chain/rpc/eth/beacon/BUILD.bazel b/beacon-chain/rpc/eth/beacon/BUILD.bazel index 382b56891040..df9877a14833 100644 --- a/beacon-chain/rpc/eth/beacon/BUILD.bazel +++ b/beacon-chain/rpc/eth/beacon/BUILD.bazel @@ -34,8 +34,8 @@ go_library( "//beacon-chain/operations/voluntaryexits:go_default_library", "//beacon-chain/p2p:go_default_library", "//beacon-chain/rpc/eth/helpers:go_default_library", + "//beacon-chain/rpc/lookup:go_default_library", "//beacon-chain/rpc/prysm/v1alpha1/validator:go_default_library", - "//beacon-chain/rpc/statefetcher:go_default_library", "//beacon-chain/state:go_default_library", "//beacon-chain/state/state-native:go_default_library", "//beacon-chain/state/stategen:go_default_library", @@ -92,7 +92,6 @@ go_test( "//beacon-chain/core/transition:go_default_library", "//beacon-chain/db:go_default_library", "//beacon-chain/db/testing:go_default_library", - "//beacon-chain/execution/testing:go_default_library", "//beacon-chain/operations/attestations:go_default_library", "//beacon-chain/operations/blstoexec:go_default_library", "//beacon-chain/operations/blstoexec/mock:go_default_library", @@ -101,12 +100,11 @@ go_test( "//beacon-chain/operations/voluntaryexits/mock:go_default_library", "//beacon-chain/p2p/testing:go_default_library", "//beacon-chain/rpc/eth/helpers:go_default_library", + "//beacon-chain/rpc/lookup:go_default_library", "//beacon-chain/rpc/prysm/v1alpha1/validator:go_default_library", - "//beacon-chain/rpc/statefetcher:go_default_library", "//beacon-chain/rpc/testutil:go_default_library", "//beacon-chain/state:go_default_library", "//beacon-chain/state/state-native:go_default_library", - "//config/features:go_default_library", "//config/params:go_default_library", "//consensus-types/blocks:go_default_library", "//consensus-types/interfaces:go_default_library", diff --git a/beacon-chain/rpc/eth/beacon/blinded_blocks.go b/beacon-chain/rpc/eth/beacon/blinded_blocks.go index 8ed7d886365b..fb13c3d51223 100644 --- a/beacon-chain/rpc/eth/beacon/blinded_blocks.go +++ b/beacon-chain/rpc/eth/beacon/blinded_blocks.go @@ -25,7 +25,7 @@ func (bs *Server) GetBlindedBlock(ctx context.Context, req *ethpbv1.BlockRequest ctx, span := trace.StartSpan(ctx, "beacon.GetBlindedBlock") defer span.End() - blk, err := bs.blockFromBlockID(ctx, req.BlockId) + blk, err := bs.Blocker.Block(ctx, req.BlockId) err = handleGetBlockError(blk, err) if err != nil { return nil, err @@ -80,7 +80,7 @@ func (bs *Server) GetBlindedBlockSSZ(ctx context.Context, req *ethpbv1.BlockRequ ctx, span := trace.StartSpan(ctx, "beacon.GetBlindedBlockSSZ") defer span.End() - blk, err := bs.blockFromBlockID(ctx, req.BlockId) + blk, err := bs.Blocker.Block(ctx, req.BlockId) err = handleGetBlockError(blk, err) if err != nil { return nil, err diff --git a/beacon-chain/rpc/eth/beacon/blinded_blocks_test.go b/beacon-chain/rpc/eth/beacon/blinded_blocks_test.go index c236c3deb1aa..c5b711612c60 100644 --- a/beacon-chain/rpc/eth/beacon/blinded_blocks_test.go +++ b/beacon-chain/rpc/eth/beacon/blinded_blocks_test.go @@ -2,17 +2,15 @@ package beacon import ( "context" - "fmt" - "reflect" "testing" mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing" builderTest "github.com/prysmaticlabs/prysm/v4/beacon-chain/builder/testing" dbTest "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing" - executionTest "github.com/prysmaticlabs/prysm/v4/beacon-chain/execution/testing" "github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/synccommittee" mockp2p "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing" "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/prysm/v1alpha1/validator" + "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/testutil" "github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/consensus-types/blocks" "github.com/prysmaticlabs/prysm/v4/encoding/bytesutil" @@ -21,7 +19,6 @@ import ( ethpbv1 "github.com/prysmaticlabs/prysm/v4/proto/eth/v1" ethpbv2 "github.com/prysmaticlabs/prysm/v4/proto/eth/v2" "github.com/prysmaticlabs/prysm/v4/proto/migration" - ethpbalpha "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1" "github.com/prysmaticlabs/prysm/v4/testing/assert" "github.com/prysmaticlabs/prysm/v4/testing/require" "github.com/prysmaticlabs/prysm/v4/testing/util" @@ -29,774 +26,284 @@ import ( ) func TestServer_GetBlindedBlock(t *testing.T) { - t.Run("Phase 0", func(t *testing.T) { - beaconDB := dbTest.SetupDB(t) - ctx := context.Background() + ctx := context.Background() - genBlk, blkContainers := fillDBTestBlocks(ctx, t, beaconDB) - canonicalRoots := make(map[[32]byte]bool) - for _, bContr := range blkContainers { - canonicalRoots[bytesutil.ToBytes32(bContr.BlockRoot)] = true - } - headBlock := blkContainers[len(blkContainers)-1] - nextSlot := headBlock.GetPhase0Block().Block.Slot + 1 - wsb, err := blocks.NewSignedBeaconBlock(headBlock.Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block) + t.Run("Phase 0", func(t *testing.T) { + b := util.NewBeaconBlock() + blk, err := blocks.NewSignedBeaconBlock(b) require.NoError(t, err) - mockChainService := &mock.ChainService{ - DB: beaconDB, - Block: wsb, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - CanonicalRoots: canonicalRoots, - FinalizedRoots: map[[32]byte]bool{}, - } + bs := &Server{ - BeaconDB: beaconDB, - ChainInfoFetcher: mockChainService, - HeadFetcher: mockChainService, - OptimisticModeFetcher: mockChainService, - FinalizationFetcher: mockChainService, + FinalizationFetcher: &mock.ChainService{}, + Blocker: &testutil.MockBlocker{BlockToReturn: blk}, } - root, err := genBlk.Block.HashTreeRoot() + expected, err := migration.V1Alpha1ToV1SignedBlock(b) require.NoError(t, err) - - tests := []struct { - name string - blockID []byte - want *ethpbalpha.SignedBeaconBlock - wantErr bool - }{ - { - name: "slot", - blockID: []byte("30"), - want: blkContainers[30].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block, - }, - { - name: "bad formatting", - blockID: []byte("3bad0"), - wantErr: true, - }, - { - name: "canonical", - blockID: []byte("30"), - want: blkContainers[30].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block, - }, - { - name: "non canonical", - blockID: []byte(fmt.Sprintf("%d", nextSlot)), - wantErr: true, - }, - { - name: "head", - blockID: []byte("head"), - want: headBlock.Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block, - }, - { - name: "finalized", - blockID: []byte("finalized"), - want: blkContainers[64].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block, - }, - { - name: "genesis", - blockID: []byte("genesis"), - want: genBlk, - }, - { - name: "genesis root", - blockID: root[:], - want: genBlk, - }, - { - name: "root", - blockID: blkContainers[20].BlockRoot, - want: blkContainers[20].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block, - }, - { - name: "non-existent root", - blockID: bytesutil.PadTo([]byte("hi there"), 32), - wantErr: true, - }, - { - name: "no block", - blockID: []byte("105"), - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - blk, err := bs.GetBlindedBlock(ctx, ðpbv1.BlockRequest{ - BlockId: tt.blockID, - }) - if tt.wantErr { - require.NotEqual(t, err, nil) - return - } - require.NoError(t, err) - - v1Block, err := migration.V1Alpha1ToV1SignedBlock(tt.want) - require.NoError(t, err) - - phase0Block, ok := blk.Data.Message.(*ethpbv2.SignedBlindedBeaconBlockContainer_Phase0Block) - require.Equal(t, true, ok) - if !reflect.DeepEqual(phase0Block.Phase0Block, v1Block.Block) { - t.Error("Expected blocks to equal") - } - assert.Equal(t, ethpbv2.Version_PHASE0, blk.Version) - }) - } + resp, err := bs.GetBlindedBlock(ctx, ðpbv1.BlockRequest{}) + require.NoError(t, err) + phase0Block, ok := resp.Data.Message.(*ethpbv2.SignedBlindedBeaconBlockContainer_Phase0Block) + require.Equal(t, true, ok) + assert.DeepEqual(t, expected.Block, phase0Block.Phase0Block) + assert.Equal(t, ethpbv2.Version_PHASE0, resp.Version) }) - t.Run("Altair", func(t *testing.T) { - beaconDB := dbTest.SetupDB(t) - ctx := context.Background() - - genBlk, blkContainers := fillDBTestBlocksAltair(ctx, t, beaconDB) - canonicalRoots := make(map[[32]byte]bool) - for _, bContr := range blkContainers { - canonicalRoots[bytesutil.ToBytes32(bContr.BlockRoot)] = true - } - headBlock := blkContainers[len(blkContainers)-1] - nextSlot := headBlock.GetAltairBlock().Block.Slot + 1 - chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetAltairBlock()) + b := util.NewBeaconBlockAltair() + blk, err := blocks.NewSignedBeaconBlock(b) require.NoError(t, err) - mockChainService := &mock.ChainService{ - DB: beaconDB, - Block: chainBlk, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - CanonicalRoots: canonicalRoots, - FinalizedRoots: map[[32]byte]bool{}, - } + bs := &Server{ - BeaconDB: beaconDB, - ChainInfoFetcher: mockChainService, - HeadFetcher: mockChainService, - OptimisticModeFetcher: mockChainService, - FinalizationFetcher: mockChainService, + FinalizationFetcher: &mock.ChainService{}, + Blocker: &testutil.MockBlocker{BlockToReturn: blk}, } - root, err := genBlk.Block.HashTreeRoot() + expected, err := migration.V1Alpha1BeaconBlockAltairToV2(b.Block) require.NoError(t, err) - - tests := []struct { - name string - blockID []byte - want *ethpbalpha.SignedBeaconBlockAltair - wantErr bool - }{ - { - name: "slot", - blockID: []byte("30"), - want: blkContainers[30].GetAltairBlock(), - }, - { - name: "bad formatting", - blockID: []byte("3bad0"), - wantErr: true, - }, - { - name: "canonical", - blockID: []byte("30"), - want: blkContainers[30].GetAltairBlock(), - }, - { - name: "non canonical", - blockID: []byte(fmt.Sprintf("%d", nextSlot)), - wantErr: true, - }, - { - name: "head", - blockID: []byte("head"), - want: headBlock.GetAltairBlock(), - }, - { - name: "finalized", - blockID: []byte("finalized"), - want: blkContainers[64].GetAltairBlock(), - }, - { - name: "genesis", - blockID: []byte("genesis"), - want: genBlk, - }, - { - name: "genesis root", - blockID: root[:], - want: genBlk, - }, - { - name: "root", - blockID: blkContainers[20].BlockRoot, - want: blkContainers[20].GetAltairBlock(), - }, - { - name: "non-existent root", - blockID: bytesutil.PadTo([]byte("hi there"), 32), - wantErr: true, - }, - { - name: "no block", - blockID: []byte("105"), - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - blk, err := bs.GetBlindedBlock(ctx, ðpbv1.BlockRequest{ - BlockId: tt.blockID, - }) - if tt.wantErr { - require.NotEqual(t, err, nil) - return - } - require.NoError(t, err) - - v2Block, err := migration.V1Alpha1BeaconBlockAltairToV2(tt.want.Block) - require.NoError(t, err) - - altairBlock, ok := blk.Data.Message.(*ethpbv2.SignedBlindedBeaconBlockContainer_AltairBlock) - require.Equal(t, true, ok) - if !reflect.DeepEqual(altairBlock.AltairBlock, v2Block) { - t.Error("Expected blocks to equal") - } - assert.Equal(t, ethpbv2.Version_ALTAIR, blk.Version) - }) - } + resp, err := bs.GetBlindedBlock(ctx, ðpbv1.BlockRequest{}) + require.NoError(t, err) + altairBlock, ok := resp.Data.Message.(*ethpbv2.SignedBlindedBeaconBlockContainer_AltairBlock) + require.Equal(t, true, ok) + assert.DeepEqual(t, expected, altairBlock.AltairBlock) + assert.Equal(t, ethpbv2.Version_ALTAIR, resp.Version) }) - t.Run("Bellatrix", func(t *testing.T) { - beaconDB := dbTest.SetupDB(t) - ctx := context.Background() - - genBlk, blkContainers := fillDBTestBlocksBellatrixBlinded(ctx, t, beaconDB) - canonicalRoots := make(map[[32]byte]bool) - for _, bContr := range blkContainers { - canonicalRoots[bytesutil.ToBytes32(bContr.BlockRoot)] = true - } - headBlock := blkContainers[len(blkContainers)-1] - nextSlot := headBlock.GetBlindedBellatrixBlock().Block.Slot + 1 - chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetBlindedBellatrixBlock()) + b := util.NewBlindedBeaconBlockBellatrix() + blk, err := blocks.NewSignedBeaconBlock(b) require.NoError(t, err) - mockChainService := &mock.ChainService{ - DB: beaconDB, - Block: chainBlk, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - CanonicalRoots: canonicalRoots, - FinalizedRoots: map[[32]byte]bool{}, - } + + mockChainService := &mock.ChainService{} bs := &Server{ - BeaconDB: beaconDB, - ChainInfoFetcher: mockChainService, - HeadFetcher: mockChainService, + FinalizationFetcher: mockChainService, + Blocker: &testutil.MockBlocker{BlockToReturn: blk}, OptimisticModeFetcher: mockChainService, - ExecutionPayloadReconstructor: &executionTest.EngineClient{ - ExecutionPayloadByBlockHash: map[[32]byte]*enginev1.ExecutionPayload{}, - }, - FinalizationFetcher: mockChainService, } - root, err := genBlk.Block.HashTreeRoot() + expected, err := migration.V1Alpha1BeaconBlockBlindedBellatrixToV2Blinded(b.Block) require.NoError(t, err) - - tests := []struct { - name string - blockID []byte - want *ethpbalpha.SignedBlindedBeaconBlockBellatrix - wantErr bool - }{ - { - name: "slot", - blockID: []byte("30"), - want: blkContainers[30].GetBlindedBellatrixBlock(), - }, - { - name: "bad formatting", - blockID: []byte("3bad0"), - wantErr: true, - }, - { - name: "canonical", - blockID: []byte("30"), - want: blkContainers[30].GetBlindedBellatrixBlock(), - }, - { - name: "non canonical", - blockID: []byte(fmt.Sprintf("%d", nextSlot)), - wantErr: true, - }, - { - name: "head", - blockID: []byte("head"), - want: headBlock.GetBlindedBellatrixBlock(), - }, - { - name: "finalized", - blockID: []byte("finalized"), - want: blkContainers[64].GetBlindedBellatrixBlock(), - }, - { - name: "genesis", - blockID: []byte("genesis"), - want: genBlk, - }, - { - name: "genesis root", - blockID: root[:], - want: genBlk, - }, - { - name: "root", - blockID: blkContainers[20].BlockRoot, - want: blkContainers[20].GetBlindedBellatrixBlock(), - }, - { - name: "non-existent root", - blockID: bytesutil.PadTo([]byte("hi there"), 32), - wantErr: true, - }, - { - name: "no block", - blockID: []byte("105"), - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - blk, err := bs.GetBlindedBlock(ctx, ðpbv1.BlockRequest{ - BlockId: tt.blockID, - }) - if tt.wantErr { - require.NotEqual(t, err, nil) - return - } - require.NoError(t, err) - - v2Block, err := migration.V1Alpha1BeaconBlockBlindedBellatrixToV2Blinded(tt.want.Block) - require.NoError(t, err) - - b, ok := blk.Data.Message.(*ethpbv2.SignedBlindedBeaconBlockContainer_BellatrixBlock) - require.Equal(t, true, ok) - if !reflect.DeepEqual(b.BellatrixBlock, v2Block) { - t.Error("Expected blocks to equal") - } - assert.Equal(t, ethpbv2.Version_BELLATRIX, blk.Version) - }) - } + resp, err := bs.GetBlindedBlock(ctx, ðpbv1.BlockRequest{}) + require.NoError(t, err) + bellatrixBlock, ok := resp.Data.Message.(*ethpbv2.SignedBlindedBeaconBlockContainer_BellatrixBlock) + require.Equal(t, true, ok) + assert.DeepEqual(t, expected, bellatrixBlock.BellatrixBlock) + assert.Equal(t, ethpbv2.Version_BELLATRIX, resp.Version) }) - t.Run("Capella", func(t *testing.T) { - beaconDB := dbTest.SetupDB(t) - ctx := context.Background() - - genBlk, blkContainers := fillDBTestBlocksCapellaBlinded(ctx, t, beaconDB) - canonicalRoots := make(map[[32]byte]bool) - for _, bContr := range blkContainers { - canonicalRoots[bytesutil.ToBytes32(bContr.BlockRoot)] = true - } - headBlock := blkContainers[len(blkContainers)-1] - nextSlot := headBlock.GetBlindedCapellaBlock().Block.Slot + 1 - chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetBlindedCapellaBlock()) + b := util.NewBlindedBeaconBlockCapella() + blk, err := blocks.NewSignedBeaconBlock(b) require.NoError(t, err) - mockChainService := &mock.ChainService{ - DB: beaconDB, - Block: chainBlk, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - CanonicalRoots: canonicalRoots, - FinalizedRoots: map[[32]byte]bool{}, - } + + mockChainService := &mock.ChainService{} bs := &Server{ - BeaconDB: beaconDB, - ChainInfoFetcher: mockChainService, - HeadFetcher: mockChainService, + FinalizationFetcher: mockChainService, + Blocker: &testutil.MockBlocker{BlockToReturn: blk}, OptimisticModeFetcher: mockChainService, - ExecutionPayloadReconstructor: &executionTest.EngineClient{ - ExecutionPayloadByBlockHash: map[[32]byte]*enginev1.ExecutionPayload{}, - }, - FinalizationFetcher: mockChainService, } - root, err := genBlk.Block.HashTreeRoot() + expected, err := migration.V1Alpha1BeaconBlockBlindedCapellaToV2Blinded(b.Block) require.NoError(t, err) - - tests := []struct { - name string - blockID []byte - want *ethpbalpha.SignedBlindedBeaconBlockCapella - wantErr bool - }{ - { - name: "slot", - blockID: []byte("30"), - want: blkContainers[30].GetBlindedCapellaBlock(), - }, - { - name: "bad formatting", - blockID: []byte("3bad0"), - wantErr: true, - }, - { - name: "canonical", - blockID: []byte("30"), - want: blkContainers[30].GetBlindedCapellaBlock(), - }, - { - name: "non canonical", - blockID: []byte(fmt.Sprintf("%d", nextSlot)), - wantErr: true, - }, - { - name: "head", - blockID: []byte("head"), - want: headBlock.GetBlindedCapellaBlock(), - }, - { - name: "finalized", - blockID: []byte("finalized"), - want: blkContainers[64].GetBlindedCapellaBlock(), - }, - { - name: "genesis", - blockID: []byte("genesis"), - want: genBlk, - }, - { - name: "genesis root", - blockID: root[:], - want: genBlk, - }, - { - name: "root", - blockID: blkContainers[20].BlockRoot, - want: blkContainers[20].GetBlindedCapellaBlock(), - }, - { - name: "non-existent root", - blockID: bytesutil.PadTo([]byte("hi there"), 32), - wantErr: true, - }, - { - name: "no block", - blockID: []byte("105"), - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - blk, err := bs.GetBlindedBlock(ctx, ðpbv1.BlockRequest{ - BlockId: tt.blockID, - }) - if tt.wantErr { - require.NotEqual(t, err, nil) - return - } - require.NoError(t, err) - - v2Block, err := migration.V1Alpha1BeaconBlockBlindedCapellaToV2Blinded(tt.want.Block) - require.NoError(t, err) - - b, ok := blk.Data.Message.(*ethpbv2.SignedBlindedBeaconBlockContainer_CapellaBlock) - require.Equal(t, true, ok) - if !reflect.DeepEqual(b.CapellaBlock, v2Block) { - t.Error("Expected blocks to equal") - } - assert.Equal(t, ethpbv2.Version_CAPELLA, blk.Version) - }) - } + resp, err := bs.GetBlindedBlock(ctx, ðpbv1.BlockRequest{}) + require.NoError(t, err) + capellaBlock, ok := resp.Data.Message.(*ethpbv2.SignedBlindedBeaconBlockContainer_CapellaBlock) + require.Equal(t, true, ok) + assert.DeepEqual(t, expected, capellaBlock.CapellaBlock) + assert.Equal(t, ethpbv2.Version_CAPELLA, resp.Version) }) - t.Run("execution optimistic", func(t *testing.T) { - beaconDB := dbTest.SetupDB(t) - ctx := context.Background() - - _, blkContainers := fillDBTestBlocksBellatrix(ctx, t, beaconDB) - headBlock := blkContainers[len(blkContainers)-1] - chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetBellatrixBlock()) + b := util.NewBlindedBeaconBlockBellatrix() + blk, err := blocks.NewSignedBeaconBlock(b) + require.NoError(t, err) + r, err := blk.Block().HashTreeRoot() require.NoError(t, err) + mockChainService := &mock.ChainService{ - DB: beaconDB, - Block: chainBlk, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - FinalizedRoots: map[[32]byte]bool{}, - OptimisticRoots: map[[32]byte]bool{ - bytesutil.ToBytes32(headBlock.BlockRoot): true, - }, + OptimisticRoots: map[[32]byte]bool{r: true}, } bs := &Server{ - BeaconDB: beaconDB, - ChainInfoFetcher: mockChainService, - HeadFetcher: mockChainService, - OptimisticModeFetcher: mockChainService, FinalizationFetcher: mockChainService, + Blocker: &testutil.MockBlocker{BlockToReturn: blk}, + OptimisticModeFetcher: mockChainService, } - blk, err := bs.GetBlindedBlock(ctx, ðpbv1.BlockRequest{ - BlockId: []byte("head"), - }) + resp, err := bs.GetBlindedBlock(ctx, ðpbv1.BlockRequest{}) require.NoError(t, err) - assert.Equal(t, true, blk.ExecutionOptimistic) + assert.Equal(t, true, resp.ExecutionOptimistic) }) - t.Run("finalized", func(t *testing.T) { - beaconDB := dbTest.SetupDB(t) - ctx := context.Background() - - _, blkContainers := fillDBTestBlocks(ctx, t, beaconDB) - headBlock := blkContainers[len(blkContainers)-1] - chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetPhase0Block()) + b := util.NewBeaconBlock() + blk, err := blocks.NewSignedBeaconBlock(b) require.NoError(t, err) + root, err := blk.Block().HashTreeRoot() + require.NoError(t, err) + mockChainService := &mock.ChainService{ - DB: beaconDB, - Block: chainBlk, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - Optimistic: true, - FinalizedRoots: map[[32]byte]bool{ - bytesutil.ToBytes32(blkContainers[32].BlockRoot): true, - bytesutil.ToBytes32(blkContainers[64].BlockRoot): false, - }, + FinalizedRoots: map[[32]byte]bool{root: true}, } bs := &Server{ - BeaconDB: beaconDB, - ChainInfoFetcher: mockChainService, - HeadFetcher: mockChainService, - OptimisticModeFetcher: mockChainService, - FinalizationFetcher: mockChainService, + FinalizationFetcher: mockChainService, + Blocker: &testutil.MockBlocker{BlockToReturn: blk}, } - t.Run("true", func(t *testing.T) { - blk, err := bs.GetBlindedBlock(ctx, ðpbv1.BlockRequest{ - BlockId: []byte("32"), - }) - require.NoError(t, err) - assert.Equal(t, true, blk.Finalized) - }) - t.Run("false", func(t *testing.T) { - blk, err := bs.GetBlindedBlock(ctx, ðpbv1.BlockRequest{ - BlockId: []byte("64"), - }) - require.NoError(t, err) - assert.Equal(t, false, blk.Finalized) - }) + resp, err := bs.GetBlindedBlock(ctx, ðpbv1.BlockRequest{BlockId: root[:]}) + require.NoError(t, err) + assert.Equal(t, true, resp.Finalized) }) -} - -func TestServer_GetBlindedBlockSSZ(t *testing.T) { - t.Run("Phase 0", func(t *testing.T) { - beaconDB := dbTest.SetupDB(t) - ctx := context.Background() - - _, blkContainers := fillDBTestBlocks(ctx, t, beaconDB) - headBlock := blkContainers[len(blkContainers)-1] - wsb, err := blocks.NewSignedBeaconBlock(headBlock.Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block) + t.Run("not finalized", func(t *testing.T) { + b := util.NewBeaconBlock() + blk, err := blocks.NewSignedBeaconBlock(b) require.NoError(t, err) + root, err := blk.Block().HashTreeRoot() + require.NoError(t, err) + mockChainService := &mock.ChainService{ - DB: beaconDB, - Block: wsb, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - FinalizedRoots: map[[32]byte]bool{}, + FinalizedRoots: map[[32]byte]bool{root: false}, } bs := &Server{ - BeaconDB: beaconDB, - ChainInfoFetcher: mockChainService, FinalizationFetcher: mockChainService, + Blocker: &testutil.MockBlocker{BlockToReturn: blk}, } - blks, err := beaconDB.BlocksBySlot(ctx, 30) - require.Equal(t, true, len(blks) > 0) + resp, err := bs.GetBlindedBlock(ctx, ðpbv1.BlockRequest{BlockId: root[:]}) require.NoError(t, err) - sszBlock, err := blks[0].MarshalSSZ() + assert.Equal(t, false, resp.Finalized) + }) +} + +func TestServer_GetBlindedBlockSSZ(t *testing.T) { + ctx := context.Background() + + t.Run("Phase 0", func(t *testing.T) { + b := util.NewBeaconBlock() + blk, err := blocks.NewSignedBeaconBlock(b) require.NoError(t, err) - resp, err := bs.GetBlindedBlockSSZ(ctx, ðpbv1.BlockRequest{BlockId: []byte("30")}) + bs := &Server{ + FinalizationFetcher: &mock.ChainService{}, + Blocker: &testutil.MockBlocker{BlockToReturn: blk}, + } + + expected, err := blk.MarshalSSZ() + require.NoError(t, err) + resp, err := bs.GetBlindedBlockSSZ(ctx, ðpbv1.BlockRequest{}) require.NoError(t, err) assert.NotNil(t, resp) - assert.DeepEqual(t, sszBlock, resp.Data) + assert.DeepEqual(t, expected, resp.Data) assert.Equal(t, ethpbv2.Version_PHASE0, resp.Version) }) - t.Run("Altair", func(t *testing.T) { - beaconDB := dbTest.SetupDB(t) - ctx := context.Background() - - _, blkContainers := fillDBTestBlocksAltair(ctx, t, beaconDB) - headBlock := blkContainers[len(blkContainers)-1] - chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetAltairBlock()) + b := util.NewBeaconBlockAltair() + blk, err := blocks.NewSignedBeaconBlock(b) require.NoError(t, err) - mockChainService := &mock.ChainService{ - DB: beaconDB, - Block: chainBlk, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - FinalizedRoots: map[[32]byte]bool{}, - } + bs := &Server{ - BeaconDB: beaconDB, - ChainInfoFetcher: mockChainService, - FinalizationFetcher: mockChainService, + FinalizationFetcher: &mock.ChainService{}, + Blocker: &testutil.MockBlocker{BlockToReturn: blk}, } - blks, err := beaconDB.BlocksBySlot(ctx, 30) - require.Equal(t, true, len(blks) > 0) - require.NoError(t, err) - sszBlock, err := blks[0].MarshalSSZ() + expected, err := blk.MarshalSSZ() require.NoError(t, err) - - resp, err := bs.GetBlindedBlockSSZ(ctx, ðpbv1.BlockRequest{BlockId: []byte("30")}) + resp, err := bs.GetBlindedBlockSSZ(ctx, ðpbv1.BlockRequest{}) require.NoError(t, err) assert.NotNil(t, resp) - assert.DeepEqual(t, sszBlock, resp.Data) + assert.DeepEqual(t, expected, resp.Data) assert.Equal(t, ethpbv2.Version_ALTAIR, resp.Version) }) - t.Run("Bellatrix", func(t *testing.T) { - beaconDB := dbTest.SetupDB(t) - ctx := context.Background() - - _, blkContainers := fillDBTestBlocksBellatrixBlinded(ctx, t, beaconDB) - headBlock := blkContainers[len(blkContainers)-1] - chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetBlindedBellatrixBlock()) + b := util.NewBlindedBeaconBlockBellatrix() + blk, err := blocks.NewSignedBeaconBlock(b) require.NoError(t, err) - mockChainService := &mock.ChainService{ - DB: beaconDB, - Block: chainBlk, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - FinalizedRoots: map[[32]byte]bool{}, - } + + mockChainService := &mock.ChainService{} bs := &Server{ - BeaconDB: beaconDB, - ChainInfoFetcher: mockChainService, - OptimisticModeFetcher: mockChainService, FinalizationFetcher: mockChainService, + Blocker: &testutil.MockBlocker{BlockToReturn: blk}, + OptimisticModeFetcher: mockChainService, } - blks, err := beaconDB.BlocksBySlot(ctx, 30) - require.Equal(t, true, len(blks) > 0) + expected, err := blk.MarshalSSZ() require.NoError(t, err) - sszBlock, err := blks[0].MarshalSSZ() - require.NoError(t, err) - - resp, err := bs.GetBlindedBlockSSZ(ctx, ðpbv1.BlockRequest{BlockId: []byte("30")}) + resp, err := bs.GetBlindedBlockSSZ(ctx, ðpbv1.BlockRequest{}) require.NoError(t, err) assert.NotNil(t, resp) - assert.DeepEqual(t, sszBlock, resp.Data) + assert.DeepEqual(t, expected, resp.Data) assert.Equal(t, ethpbv2.Version_BELLATRIX, resp.Version) }) - t.Run("Capella", func(t *testing.T) { - beaconDB := dbTest.SetupDB(t) - ctx := context.Background() - - _, blkContainers := fillDBTestBlocksCapellaBlinded(ctx, t, beaconDB) - headBlock := blkContainers[len(blkContainers)-1] - chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetBlindedCapellaBlock()) + b := util.NewBlindedBeaconBlockCapella() + blk, err := blocks.NewSignedBeaconBlock(b) require.NoError(t, err) - mockChainService := &mock.ChainService{ - DB: beaconDB, - Block: chainBlk, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - FinalizedRoots: map[[32]byte]bool{}, - } + + mockChainService := &mock.ChainService{} bs := &Server{ - BeaconDB: beaconDB, - ChainInfoFetcher: mockChainService, - OptimisticModeFetcher: mockChainService, FinalizationFetcher: mockChainService, + Blocker: &testutil.MockBlocker{BlockToReturn: blk}, + OptimisticModeFetcher: mockChainService, } - blks, err := beaconDB.BlocksBySlot(ctx, 30) - require.Equal(t, true, len(blks) > 0) + expected, err := blk.MarshalSSZ() require.NoError(t, err) - sszBlock, err := blks[0].MarshalSSZ() - require.NoError(t, err) - - resp, err := bs.GetBlindedBlockSSZ(ctx, ðpbv1.BlockRequest{BlockId: []byte("30")}) + resp, err := bs.GetBlindedBlockSSZ(ctx, ðpbv1.BlockRequest{}) require.NoError(t, err) assert.NotNil(t, resp) - assert.DeepEqual(t, sszBlock, resp.Data) + assert.DeepEqual(t, expected, resp.Data) assert.Equal(t, ethpbv2.Version_CAPELLA, resp.Version) }) - t.Run("execution optimistic", func(t *testing.T) { - beaconDB := dbTest.SetupDB(t) - ctx := context.Background() - - _, blkContainers := fillDBTestBlocksBellatrix(ctx, t, beaconDB) - headBlock := blkContainers[len(blkContainers)-1] - chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetBellatrixBlock()) + b := util.NewBlindedBeaconBlockBellatrix() + blk, err := blocks.NewSignedBeaconBlock(b) require.NoError(t, err) + r, err := blk.Block().HashTreeRoot() + require.NoError(t, err) + mockChainService := &mock.ChainService{ - DB: beaconDB, - Block: chainBlk, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - FinalizedRoots: map[[32]byte]bool{}, - OptimisticRoots: map[[32]byte]bool{ - bytesutil.ToBytes32(headBlock.BlockRoot): true, - }, + OptimisticRoots: map[[32]byte]bool{r: true}, } bs := &Server{ - BeaconDB: beaconDB, - ChainInfoFetcher: mockChainService, - HeadFetcher: mockChainService, - OptimisticModeFetcher: mockChainService, FinalizationFetcher: mockChainService, + Blocker: &testutil.MockBlocker{BlockToReturn: blk}, + OptimisticModeFetcher: mockChainService, } - blk, err := bs.GetBlindedBlockSSZ(ctx, ðpbv1.BlockRequest{ - BlockId: []byte("head"), - }) + resp, err := bs.GetBlindedBlockSSZ(ctx, ðpbv1.BlockRequest{}) require.NoError(t, err) - assert.Equal(t, true, blk.ExecutionOptimistic) + assert.Equal(t, true, resp.ExecutionOptimistic) }) - t.Run("finalized", func(t *testing.T) { - beaconDB := dbTest.SetupDB(t) - ctx := context.Background() + b := util.NewBeaconBlock() + blk, err := blocks.NewSignedBeaconBlock(b) + require.NoError(t, err) + root, err := blk.Block().HashTreeRoot() + require.NoError(t, err) - _, blkContainers := fillDBTestBlocks(ctx, t, beaconDB) - headBlock := blkContainers[len(blkContainers)-1] - chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetPhase0Block()) + mockChainService := &mock.ChainService{ + FinalizedRoots: map[[32]byte]bool{root: true}, + } + bs := &Server{ + FinalizationFetcher: mockChainService, + Blocker: &testutil.MockBlocker{BlockToReturn: blk}, + } + + resp, err := bs.GetBlindedBlockSSZ(ctx, ðpbv1.BlockRequest{BlockId: root[:]}) + require.NoError(t, err) + assert.Equal(t, true, resp.Finalized) + }) + t.Run("not finalized", func(t *testing.T) { + b := util.NewBeaconBlock() + blk, err := blocks.NewSignedBeaconBlock(b) require.NoError(t, err) + root, err := blk.Block().HashTreeRoot() + require.NoError(t, err) + mockChainService := &mock.ChainService{ - DB: beaconDB, - Block: chainBlk, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - Optimistic: true, - FinalizedRoots: map[[32]byte]bool{ - bytesutil.ToBytes32(blkContainers[32].BlockRoot): true, - bytesutil.ToBytes32(blkContainers[64].BlockRoot): false, - }, + FinalizedRoots: map[[32]byte]bool{root: false}, } bs := &Server{ - BeaconDB: beaconDB, - ChainInfoFetcher: mockChainService, - HeadFetcher: mockChainService, - OptimisticModeFetcher: mockChainService, - FinalizationFetcher: mockChainService, + FinalizationFetcher: mockChainService, + Blocker: &testutil.MockBlocker{BlockToReturn: blk}, } - t.Run("true", func(t *testing.T) { - blk, err := bs.GetBlindedBlockSSZ(ctx, ðpbv1.BlockRequest{ - BlockId: []byte("32"), - }) - require.NoError(t, err) - assert.Equal(t, true, blk.Finalized) - }) - t.Run("false", func(t *testing.T) { - blk, err := bs.GetBlindedBlockSSZ(ctx, ðpbv1.BlockRequest{ - BlockId: []byte("64"), - }) - require.NoError(t, err) - assert.Equal(t, false, blk.Finalized) - }) + resp, err := bs.GetBlindedBlockSSZ(ctx, ðpbv1.BlockRequest{BlockId: root[:]}) + require.NoError(t, err) + assert.Equal(t, false, resp.Finalized) }) } diff --git a/beacon-chain/rpc/eth/beacon/blocks.go b/beacon-chain/rpc/eth/beacon/blocks.go index 9a83b495dec1..45151955af06 100644 --- a/beacon-chain/rpc/eth/beacon/blocks.go +++ b/beacon-chain/rpc/eth/beacon/blocks.go @@ -12,6 +12,7 @@ import ( "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/helpers" "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/filters" rpchelpers "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/helpers" + "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup" fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams" "github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/consensus-types/blocks" @@ -37,23 +38,6 @@ var ( errNilBlock = errors.New("nil block") ) -// blockIdParseError represents an error scenario where a block ID could not be parsed. -type blockIdParseError struct { - message string -} - -// newBlockIdParseError creates a new error instance. -func newBlockIdParseError(reason error) blockIdParseError { - return blockIdParseError{ - message: errors.Wrapf(reason, "could not parse block ID").Error(), - } -} - -// Error returns the underlying error message. -func (e *blockIdParseError) Error() string { - return e.message -} - // GetWeakSubjectivity computes the starting epoch of the current weak subjectivity period, and then also // determines the best block root and state root to use for a Checkpoint Sync starting from that point. // DEPRECATED: GetWeakSubjectivity endpoint will no longer be supported @@ -101,7 +85,7 @@ func (bs *Server) GetBlockHeader(ctx context.Context, req *ethpbv1.BlockRequest) ctx, span := trace.StartSpan(ctx, "beacon.GetBlockHeader") defer span.End() - blk, err := bs.blockFromBlockID(ctx, req.BlockId) + blk, err := bs.Blocker.Block(ctx, req.BlockId) err = handleGetBlockError(blk, err) if err != nil { return nil, err @@ -290,7 +274,7 @@ func (bs *Server) GetBlock(ctx context.Context, req *ethpbv1.BlockRequest) (*eth ctx, span := trace.StartSpan(ctx, "beacon.GetBlock") defer span.End() - blk, err := bs.blockFromBlockID(ctx, req.BlockId) + blk, err := bs.Blocker.Block(ctx, req.BlockId) err = handleGetBlockError(blk, err) if err != nil { return nil, err @@ -314,7 +298,7 @@ func (bs *Server) GetBlockSSZ(ctx context.Context, req *ethpbv1.BlockRequest) (* ctx, span := trace.StartSpan(ctx, "beacon.GetBlockSSZ") defer span.End() - blk, err := bs.blockFromBlockID(ctx, req.BlockId) + blk, err := bs.Blocker.Block(ctx, req.BlockId) err = handleGetBlockError(blk, err) if err != nil { return nil, err @@ -336,7 +320,7 @@ func (bs *Server) GetBlockV2(ctx context.Context, req *ethpbv2.BlockRequestV2) ( ctx, span := trace.StartSpan(ctx, "beacon.GetBlockV2") defer span.End() - blk, err := bs.blockFromBlockID(ctx, req.BlockId) + blk, err := bs.Blocker.Block(ctx, req.BlockId) err = handleGetBlockError(blk, err) if err != nil { return nil, err @@ -390,7 +374,7 @@ func (bs *Server) GetBlockSSZV2(ctx context.Context, req *ethpbv2.BlockRequestV2 ctx, span := trace.StartSpan(ctx, "beacon.GetBlockSSZV2") defer span.End() - blk, err := bs.blockFromBlockID(ctx, req.BlockId) + blk, err := bs.Blocker.Block(ctx, req.BlockId) err = handleGetBlockError(blk, err) if err != nil { return nil, err @@ -532,7 +516,7 @@ func (bs *Server) ListBlockAttestations(ctx context.Context, req *ethpbv1.BlockR ctx, span := trace.StartSpan(ctx, "beacon.ListBlockAttestations") defer span.End() - blk, err := bs.blockFromBlockID(ctx, req.BlockId) + blk, err := bs.Blocker.Block(ctx, req.BlockId) err = handleGetBlockError(blk, err) if err != nil { return nil, err @@ -559,68 +543,8 @@ func (bs *Server) ListBlockAttestations(ctx context.Context, req *ethpbv1.BlockR }, nil } -func (bs *Server) blockFromBlockID(ctx context.Context, blockId []byte) (interfaces.ReadOnlySignedBeaconBlock, error) { - var err error - var blk interfaces.ReadOnlySignedBeaconBlock - switch string(blockId) { - case "head": - blk, err = bs.ChainInfoFetcher.HeadBlock(ctx) - if err != nil { - return nil, errors.Wrap(err, "could not retrieve head block") - } - case "finalized": - finalized := bs.ChainInfoFetcher.FinalizedCheckpt() - finalizedRoot := bytesutil.ToBytes32(finalized.Root) - blk, err = bs.BeaconDB.Block(ctx, finalizedRoot) - if err != nil { - return nil, errors.New("could not get finalized block from db") - } - case "genesis": - blk, err = bs.BeaconDB.GenesisBlock(ctx) - if err != nil { - return nil, errors.Wrap(err, "could not retrieve blocks for genesis slot") - } - default: - if len(blockId) == 32 { - blk, err = bs.BeaconDB.Block(ctx, bytesutil.ToBytes32(blockId)) - if err != nil { - return nil, errors.Wrap(err, "could not retrieve block") - } - } else { - slot, err := strconv.ParseUint(string(blockId), 10, 64) - if err != nil { - e := newBlockIdParseError(err) - return nil, &e - } - blks, err := bs.BeaconDB.BlocksBySlot(ctx, primitives.Slot(slot)) - if err != nil { - return nil, errors.Wrapf(err, "could not retrieve blocks for slot %d", slot) - } - _, roots, err := bs.BeaconDB.BlockRootsBySlot(ctx, primitives.Slot(slot)) - if err != nil { - return nil, errors.Wrapf(err, "could not retrieve block roots for slot %d", slot) - } - numBlks := len(blks) - if numBlks == 0 { - return nil, nil - } - for i, b := range blks { - canonical, err := bs.ChainInfoFetcher.IsCanonical(ctx, roots[i]) - if err != nil { - return nil, status.Errorf(codes.Internal, "Could not determine if block root is canonical: %v", err) - } - if canonical { - blk = b - break - } - } - } - } - return blk, nil -} - func handleGetBlockError(blk interfaces.ReadOnlySignedBeaconBlock, err error) error { - if invalidBlockIdErr, ok := err.(*blockIdParseError); ok { + if invalidBlockIdErr, ok := err.(*lookup.BlockIdParseError); ok { return status.Errorf(codes.InvalidArgument, "Invalid block ID: %v", invalidBlockIdErr) } if err != nil { diff --git a/beacon-chain/rpc/eth/beacon/blocks_test.go b/beacon-chain/rpc/eth/beacon/blocks_test.go index a8e521a6c25a..ee8a86cb63df 100644 --- a/beacon-chain/rpc/eth/beacon/blocks_test.go +++ b/beacon-chain/rpc/eth/beacon/blocks_test.go @@ -2,23 +2,19 @@ package beacon import ( "context" - "fmt" - "reflect" "testing" "github.com/prysmaticlabs/go-bitfield" mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing" "github.com/prysmaticlabs/prysm/v4/beacon-chain/db" dbTest "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing" - executionTest "github.com/prysmaticlabs/prysm/v4/beacon-chain/execution/testing" mockp2p "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing" - "github.com/prysmaticlabs/prysm/v4/config/features" + "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/testutil" "github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/consensus-types/blocks" "github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces" "github.com/prysmaticlabs/prysm/v4/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v4/encoding/bytesutil" - enginev1 "github.com/prysmaticlabs/prysm/v4/proto/engine/v1" ethpbv1 "github.com/prysmaticlabs/prysm/v4/proto/eth/v1" ethpbv2 "github.com/prysmaticlabs/prysm/v4/proto/eth/v2" "github.com/prysmaticlabs/prysm/v4/proto/migration" @@ -65,422 +61,65 @@ func fillDBTestBlocks(ctx context.Context, t *testing.T, beaconDB db.Database) ( return genBlk, blkContainers } -func fillDBTestBlocksAltair(ctx context.Context, t *testing.T, beaconDB db.Database) (*ethpbalpha.SignedBeaconBlockAltair, []*ethpbalpha.BeaconBlockContainer) { - parentRoot := [32]byte{1, 2, 3} - genBlk := util.NewBeaconBlockAltair() - genBlk.Block.ParentRoot = parentRoot[:] - root, err := genBlk.Block.HashTreeRoot() - require.NoError(t, err) - util.SaveBlock(t, ctx, beaconDB, genBlk) - require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, root)) - - count := primitives.Slot(100) - blks := make([]interfaces.ReadOnlySignedBeaconBlock, count) - blkContainers := make([]*ethpbalpha.BeaconBlockContainer, count) - for i := primitives.Slot(0); i < count; i++ { - b := util.NewBeaconBlockAltair() - b.Block.Slot = i - b.Block.ParentRoot = bytesutil.PadTo([]byte{uint8(i)}, 32) - syncCommitteeBits := bitfield.NewBitvector512() - syncCommitteeBits.SetBitAt(100, true) - b.Block.Body.SyncAggregate = ðpbalpha.SyncAggregate{ - SyncCommitteeBits: syncCommitteeBits, - SyncCommitteeSignature: bytesutil.PadTo([]byte("signature"), 96), - } - root, err := b.Block.HashTreeRoot() - require.NoError(t, err) - signedB, err := blocks.NewSignedBeaconBlock(b) - require.NoError(t, err) - blks[i] = signedB - blkContainers[i] = ðpbalpha.BeaconBlockContainer{ - Block: ðpbalpha.BeaconBlockContainer_AltairBlock{AltairBlock: b}, BlockRoot: root[:]} - } - require.NoError(t, beaconDB.SaveBlocks(ctx, blks)) - headRoot := bytesutil.ToBytes32(blkContainers[len(blks)-1].BlockRoot) - summary := ðpbalpha.StateSummary{ - Root: headRoot[:], - Slot: blkContainers[len(blks)-1].Block.(*ethpbalpha.BeaconBlockContainer_AltairBlock).AltairBlock.Block.Slot, - } - require.NoError(t, beaconDB.SaveStateSummary(ctx, summary)) - require.NoError(t, beaconDB.SaveHeadBlockRoot(ctx, headRoot)) - return genBlk, blkContainers -} - -func fillDBTestBlocksBellatrix(ctx context.Context, t *testing.T, beaconDB db.Database) (*ethpbalpha.SignedBeaconBlockBellatrix, []*ethpbalpha.BeaconBlockContainer) { - parentRoot := [32]byte{1, 2, 3} - genBlk := util.NewBeaconBlockBellatrix() - genBlk.Block.ParentRoot = parentRoot[:] - root, err := genBlk.Block.HashTreeRoot() - require.NoError(t, err) - util.SaveBlock(t, ctx, beaconDB, genBlk) - require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, root)) - - count := primitives.Slot(100) - blks := make([]interfaces.ReadOnlySignedBeaconBlock, count) - blkContainers := make([]*ethpbalpha.BeaconBlockContainer, count) - for i := primitives.Slot(0); i < count; i++ { - b := util.NewBeaconBlockBellatrix() - b.Block.Slot = i - b.Block.ParentRoot = bytesutil.PadTo([]byte{uint8(i)}, 32) - syncCommitteeBits := bitfield.NewBitvector512() - syncCommitteeBits.SetBitAt(100, true) - b.Block.Body.SyncAggregate = ðpbalpha.SyncAggregate{ - SyncCommitteeBits: syncCommitteeBits, - SyncCommitteeSignature: bytesutil.PadTo([]byte("signature"), 96), - } - b.Block.Body.ExecutionPayload = &enginev1.ExecutionPayload{ - ParentHash: bytesutil.PadTo([]byte("parent_hash"), 32), - FeeRecipient: bytesutil.PadTo([]byte("fee_recipient"), 20), - StateRoot: bytesutil.PadTo([]byte("state_root"), 32), - ReceiptsRoot: bytesutil.PadTo([]byte("receipts_root"), 32), - LogsBloom: bytesutil.PadTo([]byte("logs_bloom"), 256), - PrevRandao: bytesutil.PadTo([]byte("prev_randao"), 32), - BlockNumber: 123, - GasLimit: 123, - GasUsed: 123, - Timestamp: 123, - ExtraData: bytesutil.PadTo([]byte("extra_data"), 32), - BaseFeePerGas: bytesutil.PadTo([]byte("base_fee_per_gas"), 32), - BlockHash: bytesutil.PadTo([]byte("block_hash"), 32), - Transactions: [][]byte{[]byte("transaction1"), []byte("transaction2")}, - } - root, err := b.Block.HashTreeRoot() - require.NoError(t, err) - signedB, err := blocks.NewSignedBeaconBlock(b) - require.NoError(t, err) - blks[i] = signedB - blkContainers[i] = ðpbalpha.BeaconBlockContainer{ - Block: ðpbalpha.BeaconBlockContainer_BellatrixBlock{BellatrixBlock: b}, BlockRoot: root[:]} - } - require.NoError(t, beaconDB.SaveBlocks(ctx, blks)) - headRoot := bytesutil.ToBytes32(blkContainers[len(blks)-1].BlockRoot) - summary := ðpbalpha.StateSummary{ - Root: headRoot[:], - Slot: blkContainers[len(blks)-1].Block.(*ethpbalpha.BeaconBlockContainer_BellatrixBlock).BellatrixBlock.Block.Slot, - } - require.NoError(t, beaconDB.SaveStateSummary(ctx, summary)) - require.NoError(t, beaconDB.SaveHeadBlockRoot(ctx, headRoot)) - return genBlk, blkContainers -} - -func fillDBTestBlocksCapella(ctx context.Context, t *testing.T, beaconDB db.Database) (*ethpbalpha.SignedBeaconBlockCapella, []*ethpbalpha.BeaconBlockContainer) { - parentRoot := [32]byte{1, 2, 3} - genBlk := util.NewBeaconBlockCapella() - genBlk.Block.ParentRoot = parentRoot[:] - root, err := genBlk.Block.HashTreeRoot() - require.NoError(t, err) - util.SaveBlock(t, ctx, beaconDB, genBlk) - require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, root)) - - count := primitives.Slot(100) - blks := make([]interfaces.ReadOnlySignedBeaconBlock, count) - blkContainers := make([]*ethpbalpha.BeaconBlockContainer, count) - for i := primitives.Slot(0); i < count; i++ { - b := util.NewBeaconBlockCapella() - b.Block.Slot = i - b.Block.ParentRoot = bytesutil.PadTo([]byte{uint8(i)}, 32) - syncCommitteeBits := bitfield.NewBitvector512() - syncCommitteeBits.SetBitAt(100, true) - b.Block.Body.SyncAggregate = ðpbalpha.SyncAggregate{ - SyncCommitteeBits: syncCommitteeBits, - SyncCommitteeSignature: bytesutil.PadTo([]byte("signature"), 96), - } - b.Block.Body.ExecutionPayload = &enginev1.ExecutionPayloadCapella{ - ParentHash: bytesutil.PadTo([]byte("parent_hash"), 32), - FeeRecipient: bytesutil.PadTo([]byte("fee_recipient"), 20), - StateRoot: bytesutil.PadTo([]byte("state_root"), 32), - ReceiptsRoot: bytesutil.PadTo([]byte("receipts_root"), 32), - LogsBloom: bytesutil.PadTo([]byte("logs_bloom"), 256), - PrevRandao: bytesutil.PadTo([]byte("prev_randao"), 32), - BlockNumber: 123, - GasLimit: 123, - GasUsed: 123, - Timestamp: 123, - ExtraData: bytesutil.PadTo([]byte("extra_data"), 32), - BaseFeePerGas: bytesutil.PadTo([]byte("base_fee_per_gas"), 32), - BlockHash: bytesutil.PadTo([]byte("block_hash"), 32), - Transactions: [][]byte{[]byte("transaction1"), []byte("transaction2")}, - Withdrawals: []*enginev1.Withdrawal{ - { - Index: 1, - ValidatorIndex: 1, - Address: bytesutil.PadTo([]byte("address1"), 20), - Amount: 1, - }, - { - Index: 2, - ValidatorIndex: 2, - Address: bytesutil.PadTo([]byte("address2"), 20), - Amount: 2, - }, - }, - } - root, err := b.Block.HashTreeRoot() - require.NoError(t, err) - signedB, err := blocks.NewSignedBeaconBlock(b) - require.NoError(t, err) - blks[i] = signedB - blkContainers[i] = ðpbalpha.BeaconBlockContainer{ - Block: ðpbalpha.BeaconBlockContainer_CapellaBlock{CapellaBlock: b}, BlockRoot: root[:]} - } - require.NoError(t, beaconDB.SaveBlocks(ctx, blks)) - headRoot := bytesutil.ToBytes32(blkContainers[len(blks)-1].BlockRoot) - summary := ðpbalpha.StateSummary{ - Root: headRoot[:], - Slot: blkContainers[len(blks)-1].Block.(*ethpbalpha.BeaconBlockContainer_CapellaBlock).CapellaBlock.Block.Slot, - } - require.NoError(t, beaconDB.SaveStateSummary(ctx, summary)) - require.NoError(t, beaconDB.SaveHeadBlockRoot(ctx, headRoot)) - return genBlk, blkContainers -} - -func fillDBTestBlocksBellatrixBlinded(ctx context.Context, t *testing.T, beaconDB db.Database) (*ethpbalpha.SignedBlindedBeaconBlockBellatrix, []*ethpbalpha.BeaconBlockContainer) { - parentRoot := [32]byte{1, 2, 3} - genBlk := util.NewBlindedBeaconBlockBellatrix() - genBlk.Block.ParentRoot = parentRoot[:] - root, err := genBlk.Block.HashTreeRoot() - require.NoError(t, err) - util.SaveBlock(t, ctx, beaconDB, genBlk) - require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, root)) - - count := primitives.Slot(100) - blks := make([]interfaces.ReadOnlySignedBeaconBlock, count) - blkContainers := make([]*ethpbalpha.BeaconBlockContainer, count) - for i := primitives.Slot(0); i < count; i++ { - b := util.NewBlindedBeaconBlockBellatrix() - b.Block.Slot = i - b.Block.ParentRoot = bytesutil.PadTo([]byte{uint8(i)}, 32) - syncCommitteeBits := bitfield.NewBitvector512() - syncCommitteeBits.SetBitAt(100, true) - b.Block.Body.SyncAggregate = ðpbalpha.SyncAggregate{ - SyncCommitteeBits: syncCommitteeBits, - SyncCommitteeSignature: bytesutil.PadTo([]byte("signature"), 96), - } - b.Block.Body.ExecutionPayloadHeader = &enginev1.ExecutionPayloadHeader{ - ParentHash: bytesutil.PadTo([]byte("parent_hash"), 32), - FeeRecipient: bytesutil.PadTo([]byte("fee_recipient"), 20), - StateRoot: bytesutil.PadTo([]byte("state_root"), 32), - ReceiptsRoot: bytesutil.PadTo([]byte("receipts_root"), 32), - LogsBloom: bytesutil.PadTo([]byte("logs_bloom"), 256), - PrevRandao: bytesutil.PadTo([]byte("prev_randao"), 32), - BlockNumber: 123, - GasLimit: 123, - GasUsed: 123, - Timestamp: 123, - ExtraData: bytesutil.PadTo([]byte("extra_data"), 32), - BaseFeePerGas: bytesutil.PadTo([]byte("base_fee_per_gas"), 32), - BlockHash: bytesutil.PadTo([]byte("block_hash"), 32), - TransactionsRoot: bytesutil.PadTo([]byte("transactions_root"), 32), - } - root, err := b.Block.HashTreeRoot() - require.NoError(t, err) - signedB, err := blocks.NewSignedBeaconBlock(b) - require.NoError(t, err) - blks[i] = signedB - blkContainers[i] = ðpbalpha.BeaconBlockContainer{ - Block: ðpbalpha.BeaconBlockContainer_BlindedBellatrixBlock{BlindedBellatrixBlock: b}, BlockRoot: root[:]} - } - require.NoError(t, beaconDB.SaveBlocks(ctx, blks)) - headRoot := bytesutil.ToBytes32(blkContainers[len(blks)-1].BlockRoot) - summary := ðpbalpha.StateSummary{ - Root: headRoot[:], - Slot: blkContainers[len(blks)-1].Block.(*ethpbalpha.BeaconBlockContainer_BlindedBellatrixBlock).BlindedBellatrixBlock.Block.Slot, - } - require.NoError(t, beaconDB.SaveStateSummary(ctx, summary)) - require.NoError(t, beaconDB.SaveHeadBlockRoot(ctx, headRoot)) - return genBlk, blkContainers -} - -func fillDBTestBlocksCapellaBlinded(ctx context.Context, t *testing.T, beaconDB db.Database) (*ethpbalpha.SignedBlindedBeaconBlockCapella, []*ethpbalpha.BeaconBlockContainer) { - parentRoot := [32]byte{1, 2, 3} - genBlk := util.NewBlindedBeaconBlockCapella() - genBlk.Block.ParentRoot = parentRoot[:] - root, err := genBlk.Block.HashTreeRoot() - require.NoError(t, err) - util.SaveBlock(t, ctx, beaconDB, genBlk) - require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, root)) - - count := primitives.Slot(100) - blks := make([]interfaces.ReadOnlySignedBeaconBlock, count) - blkContainers := make([]*ethpbalpha.BeaconBlockContainer, count) - for i := primitives.Slot(0); i < count; i++ { - b := util.NewBlindedBeaconBlockCapella() - b.Block.Slot = i - b.Block.ParentRoot = bytesutil.PadTo([]byte{uint8(i)}, 32) - syncCommitteeBits := bitfield.NewBitvector512() - syncCommitteeBits.SetBitAt(100, true) - b.Block.Body.SyncAggregate = ðpbalpha.SyncAggregate{ - SyncCommitteeBits: syncCommitteeBits, - SyncCommitteeSignature: bytesutil.PadTo([]byte("signature"), 96), - } - b.Block.Body.ExecutionPayloadHeader = &enginev1.ExecutionPayloadHeaderCapella{ - ParentHash: bytesutil.PadTo([]byte("parent_hash"), 32), - FeeRecipient: bytesutil.PadTo([]byte("fee_recipient"), 20), - StateRoot: bytesutil.PadTo([]byte("state_root"), 32), - ReceiptsRoot: bytesutil.PadTo([]byte("receipts_root"), 32), - LogsBloom: bytesutil.PadTo([]byte("logs_bloom"), 256), - PrevRandao: bytesutil.PadTo([]byte("prev_randao"), 32), - BlockNumber: 123, - GasLimit: 123, - GasUsed: 123, - Timestamp: 123, - ExtraData: bytesutil.PadTo([]byte("extra_data"), 32), - BaseFeePerGas: bytesutil.PadTo([]byte("base_fee_per_gas"), 32), - BlockHash: bytesutil.PadTo([]byte("block_hash"), 32), - TransactionsRoot: bytesutil.PadTo([]byte("transactions_root"), 32), - WithdrawalsRoot: bytesutil.PadTo([]byte("withdrawals_root"), 32), - } - root, err := b.Block.HashTreeRoot() - require.NoError(t, err) - signedB, err := blocks.NewSignedBeaconBlock(b) - require.NoError(t, err) - blks[i] = signedB - blkContainers[i] = ðpbalpha.BeaconBlockContainer{ - Block: ðpbalpha.BeaconBlockContainer_BlindedCapellaBlock{BlindedCapellaBlock: b}, BlockRoot: root[:]} - } - require.NoError(t, beaconDB.SaveBlocks(ctx, blks)) - headRoot := bytesutil.ToBytes32(blkContainers[len(blks)-1].BlockRoot) - summary := ðpbalpha.StateSummary{ - Root: headRoot[:], - Slot: blkContainers[len(blks)-1].Block.(*ethpbalpha.BeaconBlockContainer_BlindedCapellaBlock).BlindedCapellaBlock.Block.Slot, - } - require.NoError(t, beaconDB.SaveStateSummary(ctx, summary)) - require.NoError(t, beaconDB.SaveHeadBlockRoot(ctx, headRoot)) - return genBlk, blkContainers -} - func TestServer_GetBlockHeader(t *testing.T) { - beaconDB := dbTest.SetupDB(t) ctx := context.Background() - - genBlk, blkContainers := fillDBTestBlocks(ctx, t, beaconDB) - root, err := genBlk.Block.HashTreeRoot() + b := util.NewBeaconBlock() + b.Block.Slot = 123 + b.Block.ProposerIndex = 123 + b.Block.StateRoot = bytesutil.PadTo([]byte("stateroot"), 32) + sb, err := blocks.NewSignedBeaconBlock(b) require.NoError(t, err) - headBlock := blkContainers[len(blkContainers)-1] + mockBlockFetcher := &testutil.MockBlocker{BlockToReturn: sb} t.Run("get header", func(t *testing.T) { - wsb, err := blocks.NewSignedBeaconBlock(headBlock.Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block) - require.NoError(t, err) mockChainService := &mock.ChainService{ - DB: beaconDB, - Block: wsb, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - FinalizedRoots: map[[32]byte]bool{}, + FinalizedRoots: map[[32]byte]bool{}, } bs := &Server{ - BeaconDB: beaconDB, ChainInfoFetcher: mockChainService, - HeadFetcher: mockChainService, OptimisticModeFetcher: mockChainService, FinalizationFetcher: mockChainService, + Blocker: mockBlockFetcher, } - tests := []struct { - name string - blockID []byte - want *ethpbalpha.SignedBeaconBlock - wantErr bool - }{ - { - name: "slot", - blockID: []byte("10"), - want: blkContainers[10].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block, - }, - { - name: "root", - blockID: blkContainers[20].BlockRoot, - want: blkContainers[20].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block, - }, - { - name: "canonical", - blockID: []byte("30"), - want: blkContainers[30].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block, - }, - { - name: "genesis", - blockID: []byte("genesis"), - want: genBlk, - }, - { - name: "genesis root", - blockID: root[:], - want: genBlk, - }, - { - name: "head", - blockID: []byte("head"), - want: headBlock.Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block, - }, - { - name: "finalized", - blockID: []byte("finalized"), - want: blkContainers[64].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block, - }, - { - name: "no block", - blockID: []byte("105"), - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - header, err := bs.GetBlockHeader(ctx, ðpbv1.BlockRequest{ - BlockId: tt.blockID, - }) - if !tt.wantErr { - require.NoError(t, err) - } else { - require.NotEqual(t, err, nil) - return - } - - expectedBodyRoot, err := tt.want.Block.Body.HashTreeRoot() - require.NoError(t, err) - expectedHeader := ðpbv1.BeaconBlockHeader{ - Slot: tt.want.Block.Slot, - ProposerIndex: tt.want.Block.ProposerIndex, - ParentRoot: tt.want.Block.ParentRoot, - StateRoot: make([]byte, 32), - BodyRoot: expectedBodyRoot[:], - } - expectedHeaderRoot, err := expectedHeader.HashTreeRoot() - require.NoError(t, err) - headerRoot, err := header.Data.Header.Message.HashTreeRoot() - require.NoError(t, err) - assert.DeepEqual(t, expectedHeaderRoot, headerRoot) + header, err := bs.GetBlockHeader(ctx, ðpbv1.BlockRequest{}) + require.NoError(t, err) - assert.Equal(t, tt.want.Block.Slot, header.Data.Header.Message.Slot) - assert.DeepEqual(t, tt.want.Block.StateRoot, header.Data.Header.Message.StateRoot) - assert.DeepEqual(t, tt.want.Block.ParentRoot, header.Data.Header.Message.ParentRoot) - expectedRoot, err := tt.want.Block.Body.HashTreeRoot() - require.NoError(t, err) - assert.DeepEqual(t, expectedRoot[:], header.Data.Header.Message.BodyRoot) - assert.Equal(t, tt.want.Block.ProposerIndex, header.Data.Header.Message.ProposerIndex) - }) + expectedBodyRoot, err := sb.Block().Body().HashTreeRoot() + require.NoError(t, err) + expectedParentRoot := sb.Block().ParentRoot() + expectedHeader := ðpbv1.BeaconBlockHeader{ + Slot: sb.Block().Slot(), + ProposerIndex: sb.Block().ProposerIndex(), + ParentRoot: expectedParentRoot[:], + StateRoot: bytesutil.PadTo([]byte("stateroot"), 32), + BodyRoot: expectedBodyRoot[:], } + expectedHeaderRoot, err := expectedHeader.HashTreeRoot() + require.NoError(t, err) + headerRoot, err := header.Data.Header.Message.HashTreeRoot() + require.NoError(t, err) + assert.DeepEqual(t, expectedHeaderRoot, headerRoot) + assert.Equal(t, sb.Block().Slot(), header.Data.Header.Message.Slot) + expectedStateRoot := sb.Block().StateRoot() + assert.DeepEqual(t, expectedStateRoot[:], header.Data.Header.Message.StateRoot) + assert.DeepEqual(t, expectedParentRoot[:], header.Data.Header.Message.ParentRoot) + assert.DeepEqual(t, expectedBodyRoot[:], header.Data.Header.Message.BodyRoot) + assert.Equal(t, sb.Block().ProposerIndex(), header.Data.Header.Message.ProposerIndex) }) t.Run("execution optimistic", func(t *testing.T) { - wsb, err := blocks.NewSignedBeaconBlock(headBlock.Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block) + r, err := sb.Block().HashTreeRoot() require.NoError(t, err) mockChainService := &mock.ChainService{ - DB: beaconDB, - Block: wsb, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - Optimistic: true, - FinalizedRoots: map[[32]byte]bool{}, - OptimisticRoots: map[[32]byte]bool{ - bytesutil.ToBytes32(headBlock.BlockRoot): true, - }, + OptimisticRoots: map[[32]byte]bool{r: true}, + FinalizedRoots: map[[32]byte]bool{}, } bs := &Server{ - BeaconDB: beaconDB, ChainInfoFetcher: mockChainService, - HeadFetcher: mockChainService, OptimisticModeFetcher: mockChainService, FinalizationFetcher: mockChainService, + Blocker: mockBlockFetcher, } header, err := bs.GetBlockHeader(ctx, ðpbv1.BlockRequest{BlockId: []byte("head")}) require.NoError(t, err) @@ -488,33 +127,32 @@ func TestServer_GetBlockHeader(t *testing.T) { }) t.Run("finalized", func(t *testing.T) { - wsb, err := blocks.NewSignedBeaconBlock(headBlock.Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block) + r, err := sb.Block().HashTreeRoot() require.NoError(t, err) - mockChainService := &mock.ChainService{ - DB: beaconDB, - Block: wsb, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - FinalizedRoots: map[[32]byte]bool{ - bytesutil.ToBytes32(blkContainers[32].BlockRoot): true, - bytesutil.ToBytes32(blkContainers[64].BlockRoot): false, - }, - } - bs := &Server{ - BeaconDB: beaconDB, - ChainInfoFetcher: mockChainService, - HeadFetcher: mockChainService, - OptimisticModeFetcher: mockChainService, - FinalizationFetcher: mockChainService, - } t.Run("true", func(t *testing.T) { - header, err := bs.GetBlockHeader(ctx, ðpbv1.BlockRequest{BlockId: blkContainers[32].BlockRoot}) + mockChainService := &mock.ChainService{FinalizedRoots: map[[32]byte]bool{r: true}} + bs := &Server{ + ChainInfoFetcher: mockChainService, + OptimisticModeFetcher: mockChainService, + FinalizationFetcher: mockChainService, + Blocker: mockBlockFetcher, + } + + header, err := bs.GetBlockHeader(ctx, ðpbv1.BlockRequest{BlockId: r[:]}) require.NoError(t, err) assert.Equal(t, true, header.Finalized) }) t.Run("false", func(t *testing.T) { - header, err := bs.GetBlockHeader(ctx, ðpbv1.BlockRequest{BlockId: blkContainers[64].BlockRoot}) + mockChainService := &mock.ChainService{FinalizedRoots: map[[32]byte]bool{r: false}} + bs := &Server{ + ChainInfoFetcher: mockChainService, + OptimisticModeFetcher: mockChainService, + FinalizationFetcher: mockChainService, + Blocker: mockBlockFetcher, + } + + header, err := bs.GetBlockHeader(ctx, ðpbv1.BlockRequest{BlockId: r[:]}) require.NoError(t, err) assert.Equal(t, false, header.Finalized) }) @@ -558,7 +196,6 @@ func TestServer_ListBlockHeaders(t *testing.T) { bs := &Server{ BeaconDB: beaconDB, ChainInfoFetcher: mockChainFetcher, - HeadFetcher: mockChainFetcher, OptimisticModeFetcher: mockChainFetcher, FinalizationFetcher: mockChainFetcher, } @@ -644,7 +281,6 @@ func TestServer_ListBlockHeaders(t *testing.T) { bs := &Server{ BeaconDB: beaconDB, ChainInfoFetcher: mockChainFetcher, - HeadFetcher: mockChainFetcher, OptimisticModeFetcher: mockChainFetcher, FinalizationFetcher: mockChainFetcher, } @@ -681,7 +317,6 @@ func TestServer_ListBlockHeaders(t *testing.T) { bs := &Server{ BeaconDB: beaconDB, ChainInfoFetcher: mockChainFetcher, - HeadFetcher: mockChainFetcher, OptimisticModeFetcher: mockChainFetcher, FinalizationFetcher: mockChainFetcher, } @@ -1038,1420 +673,414 @@ func TestServer_SubmitBlockSSZ_OK(t *testing.T) { } func TestServer_GetBlock(t *testing.T) { - beaconDB := dbTest.SetupDB(t) ctx := context.Background() - - genBlk, blkContainers := fillDBTestBlocks(ctx, t, beaconDB) - canonicalRoots := make(map[[32]byte]bool) - - for _, bContr := range blkContainers { - canonicalRoots[bytesutil.ToBytes32(bContr.BlockRoot)] = true - } - headBlock := blkContainers[len(blkContainers)-1] - nextSlot := headBlock.GetPhase0Block().Block.Slot + 1 - - b2 := util.NewBeaconBlock() - b2.Block.Slot = 30 - b2.Block.ParentRoot = bytesutil.PadTo([]byte{1}, 32) - util.SaveBlock(t, ctx, beaconDB, b2) - b3 := util.NewBeaconBlock() - b3.Block.Slot = 30 - b3.Block.ParentRoot = bytesutil.PadTo([]byte{4}, 32) - util.SaveBlock(t, ctx, beaconDB, b3) - b4 := util.NewBeaconBlock() - b4.Block.Slot = nextSlot - b4.Block.ParentRoot = bytesutil.PadTo([]byte{8}, 32) - util.SaveBlock(t, ctx, beaconDB, b4) - - wsb, err := blocks.NewSignedBeaconBlock(headBlock.Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block) + b := util.NewBeaconBlock() + b.Block.Slot = 123 + sb, err := blocks.NewSignedBeaconBlock(b) require.NoError(t, err) - bs := &Server{ - BeaconDB: beaconDB, - ChainInfoFetcher: &mock.ChainService{ - DB: beaconDB, - Block: wsb, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - CanonicalRoots: canonicalRoots, - }, + Blocker: &testutil.MockBlocker{BlockToReturn: sb}, } - root, err := genBlk.Block.HashTreeRoot() + blk, err := bs.GetBlock(ctx, ðpbv1.BlockRequest{}) require.NoError(t, err) - - tests := []struct { - name string - blockID []byte - want *ethpbalpha.SignedBeaconBlock - wantErr bool - }{ - { - name: "slot", - blockID: []byte("30"), - want: blkContainers[30].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block, - }, - { - name: "bad formatting", - blockID: []byte("3bad0"), - wantErr: true, - }, - { - name: "canonical", - blockID: []byte("30"), - want: blkContainers[30].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block, - }, - { - name: "non canonical", - blockID: []byte(fmt.Sprintf("%d", nextSlot)), - wantErr: true, - }, - { - name: "head", - blockID: []byte("head"), - want: headBlock.Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block, - }, - { - name: "finalized", - blockID: []byte("finalized"), - want: blkContainers[64].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block, - }, - { - name: "genesis", - blockID: []byte("genesis"), - want: genBlk, - }, - { - name: "genesis root", - blockID: root[:], - want: genBlk, - }, - { - name: "root", - blockID: blkContainers[20].BlockRoot, - want: blkContainers[20].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block, - }, - { - name: "non-existent root", - blockID: bytesutil.PadTo([]byte("hi there"), 32), - wantErr: true, - }, - { - name: "no block", - blockID: []byte("105"), - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - blk, err := bs.GetBlock(ctx, ðpbv1.BlockRequest{ - BlockId: tt.blockID, - }) - if tt.wantErr { - require.NotEqual(t, err, nil, "no error has been returned") - return - } - require.NoError(t, err) - - v1Block, err := migration.V1Alpha1ToV1SignedBlock(tt.want) - require.NoError(t, err) - - if !reflect.DeepEqual(blk.Data.Message, v1Block.Block) { - t.Error("Expected blocks to equal") - } - }) - } + v1Block, err := migration.V1Alpha1ToV1SignedBlock(b) + require.NoError(t, err) + assert.DeepEqual(t, v1Block.Block, blk.Data.Message) } func TestServer_GetBlockV2(t *testing.T) { - t.Run("Phase 0", func(t *testing.T) { - beaconDB := dbTest.SetupDB(t) - ctx := context.Background() - - genBlk, blkContainers := fillDBTestBlocks(ctx, t, beaconDB) - canonicalRoots := make(map[[32]byte]bool) - for _, bContr := range blkContainers { - canonicalRoots[bytesutil.ToBytes32(bContr.BlockRoot)] = true - } - headBlock := blkContainers[len(blkContainers)-1] - nextSlot := headBlock.GetPhase0Block().Block.Slot + 1 + ctx := context.Background() - wsb, err := blocks.NewSignedBeaconBlock(headBlock.Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block) + t.Run("Phase 0", func(t *testing.T) { + b := util.NewBeaconBlock() + b.Block.Slot = 123 + sb, err := blocks.NewSignedBeaconBlock(b) require.NoError(t, err) - + mockBlockFetcher := &testutil.MockBlocker{BlockToReturn: sb} mockChainService := &mock.ChainService{ - DB: beaconDB, - Block: wsb, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - CanonicalRoots: canonicalRoots, - FinalizedRoots: map[[32]byte]bool{}, + FinalizedRoots: map[[32]byte]bool{}, } bs := &Server{ - BeaconDB: beaconDB, - ChainInfoFetcher: mockChainService, - HeadFetcher: mockChainService, - OptimisticModeFetcher: mockChainService, - FinalizationFetcher: mockChainService, + FinalizationFetcher: mockChainService, + Blocker: mockBlockFetcher, } - root, err := genBlk.Block.HashTreeRoot() + blk, err := bs.GetBlockV2(ctx, ðpbv2.BlockRequestV2{}) require.NoError(t, err) - tests := []struct { - name string - blockID []byte - want *ethpbalpha.SignedBeaconBlock - wantErr bool - }{ - { - name: "slot", - blockID: []byte("30"), - want: blkContainers[30].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block, - }, - { - name: "bad formatting", - blockID: []byte("3bad0"), - wantErr: true, - }, - { - name: "canonical", - blockID: []byte("30"), - want: blkContainers[30].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block, - }, - { - name: "non canonical", - blockID: []byte(fmt.Sprintf("%d", nextSlot)), - wantErr: true, - }, - { - name: "head", - blockID: []byte("head"), - want: headBlock.Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block, - }, - { - name: "finalized", - blockID: []byte("finalized"), - want: blkContainers[64].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block, - }, - { - name: "genesis", - blockID: []byte("genesis"), - want: genBlk, - }, - { - name: "genesis root", - blockID: root[:], - want: genBlk, - }, - { - name: "root", - blockID: blkContainers[20].BlockRoot, - want: blkContainers[20].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block, - }, - { - name: "non-existent root", - blockID: bytesutil.PadTo([]byte("hi there"), 32), - wantErr: true, - }, - { - name: "no block", - blockID: []byte("105"), - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - blk, err := bs.GetBlockV2(ctx, ðpbv2.BlockRequestV2{ - BlockId: tt.blockID, - }) - if tt.wantErr { - require.NotEqual(t, err, nil) - return - } - require.NoError(t, err) - - v1Block, err := migration.V1Alpha1ToV1SignedBlock(tt.want) - require.NoError(t, err) - - phase0Block, ok := blk.Data.Message.(*ethpbv2.SignedBeaconBlockContainer_Phase0Block) - require.Equal(t, true, ok) - if !reflect.DeepEqual(phase0Block.Phase0Block, v1Block.Block) { - t.Error("Expected blocks to equal") - } - assert.Equal(t, ethpbv2.Version_PHASE0, blk.Version) - }) - } + v1Block, err := migration.V1Alpha1ToV1SignedBlock(b) + require.NoError(t, err) + phase0Block, ok := blk.Data.Message.(*ethpbv2.SignedBeaconBlockContainer_Phase0Block) + require.Equal(t, true, ok) + assert.DeepEqual(t, v1Block.Block, phase0Block.Phase0Block) + assert.Equal(t, ethpbv2.Version_PHASE0, blk.Version) }) - t.Run("Altair", func(t *testing.T) { - beaconDB := dbTest.SetupDB(t) - ctx := context.Background() - - genBlk, blkContainers := fillDBTestBlocksAltair(ctx, t, beaconDB) - canonicalRoots := make(map[[32]byte]bool) - for _, bContr := range blkContainers { - canonicalRoots[bytesutil.ToBytes32(bContr.BlockRoot)] = true + b := util.NewBeaconBlockAltair() + b.Block.Slot = 123 + sb, err := blocks.NewSignedBeaconBlock(b) + require.NoError(t, err) + mockBlockFetcher := &testutil.MockBlocker{BlockToReturn: sb} + mockChainService := &mock.ChainService{ + FinalizedRoots: map[[32]byte]bool{}, + } + bs := &Server{ + FinalizationFetcher: mockChainService, + Blocker: mockBlockFetcher, } - headBlock := blkContainers[len(blkContainers)-1] - nextSlot := headBlock.GetAltairBlock().Block.Slot + 1 - chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetAltairBlock()) + blk, err := bs.GetBlockV2(ctx, ðpbv2.BlockRequestV2{}) + require.NoError(t, err) + + v1Block, err := migration.V1Alpha1BeaconBlockAltairToV2(b.Block) + require.NoError(t, err) + altairBlock, ok := blk.Data.Message.(*ethpbv2.SignedBeaconBlockContainer_AltairBlock) + require.Equal(t, true, ok) + assert.DeepEqual(t, v1Block, altairBlock.AltairBlock) + assert.Equal(t, ethpbv2.Version_ALTAIR, blk.Version) + }) + t.Run("Bellatrix", func(t *testing.T) { + b := util.NewBeaconBlockBellatrix() + b.Block.Slot = 123 + sb, err := blocks.NewSignedBeaconBlock(b) require.NoError(t, err) + mockBlockFetcher := &testutil.MockBlocker{BlockToReturn: sb} mockChainService := &mock.ChainService{ - DB: beaconDB, - Block: chainBlk, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - CanonicalRoots: canonicalRoots, - FinalizedRoots: map[[32]byte]bool{}, + FinalizedRoots: map[[32]byte]bool{}, } bs := &Server{ - BeaconDB: beaconDB, - ChainInfoFetcher: mockChainService, - HeadFetcher: mockChainService, OptimisticModeFetcher: mockChainService, FinalizationFetcher: mockChainService, + Blocker: mockBlockFetcher, } - root, err := genBlk.Block.HashTreeRoot() + blk, err := bs.GetBlockV2(ctx, ðpbv2.BlockRequestV2{}) require.NoError(t, err) - tests := []struct { - name string - blockID []byte - want *ethpbalpha.SignedBeaconBlockAltair - wantErr bool - }{ - { - name: "slot", - blockID: []byte("30"), - want: blkContainers[30].GetAltairBlock(), - }, - { - name: "bad formatting", - blockID: []byte("3bad0"), - wantErr: true, - }, - { - name: "canonical", - blockID: []byte("30"), - want: blkContainers[30].GetAltairBlock(), - }, - { - name: "non canonical", - blockID: []byte(fmt.Sprintf("%d", nextSlot)), - wantErr: true, - }, - { - name: "head", - blockID: []byte("head"), - want: headBlock.GetAltairBlock(), - }, - { - name: "finalized", - blockID: []byte("finalized"), - want: blkContainers[64].GetAltairBlock(), - }, - { - name: "genesis", - blockID: []byte("genesis"), - want: genBlk, - }, - { - name: "genesis root", - blockID: root[:], - want: genBlk, - }, - { - name: "root", - blockID: blkContainers[20].BlockRoot, - want: blkContainers[20].GetAltairBlock(), - }, - { - name: "non-existent root", - blockID: bytesutil.PadTo([]byte("hi there"), 32), - wantErr: true, - }, - { - name: "no block", - blockID: []byte("105"), - wantErr: true, - }, + v1Block, err := migration.V1Alpha1BeaconBlockBellatrixToV2(b.Block) + require.NoError(t, err) + bellatrixBlock, ok := blk.Data.Message.(*ethpbv2.SignedBeaconBlockContainer_BellatrixBlock) + require.Equal(t, true, ok) + assert.DeepEqual(t, v1Block, bellatrixBlock.BellatrixBlock) + assert.Equal(t, ethpbv2.Version_BELLATRIX, blk.Version) + }) + t.Run("Capella", func(t *testing.T) { + b := util.NewBeaconBlockCapella() + b.Block.Slot = 123 + sb, err := blocks.NewSignedBeaconBlock(b) + require.NoError(t, err) + mockBlockFetcher := &testutil.MockBlocker{BlockToReturn: sb} + mockChainService := &mock.ChainService{ + FinalizedRoots: map[[32]byte]bool{}, } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - blk, err := bs.GetBlockV2(ctx, ðpbv2.BlockRequestV2{ - BlockId: tt.blockID, - }) - if tt.wantErr { - require.NotEqual(t, err, nil) - return - } - require.NoError(t, err) - - v2Block, err := migration.V1Alpha1BeaconBlockAltairToV2(tt.want.Block) - require.NoError(t, err) - - altairBlock, ok := blk.Data.Message.(*ethpbv2.SignedBeaconBlockContainer_AltairBlock) - require.Equal(t, true, ok) - if !reflect.DeepEqual(altairBlock.AltairBlock, v2Block) { - t.Error("Expected blocks to equal") - } - assert.Equal(t, ethpbv2.Version_ALTAIR, blk.Version) - }) + bs := &Server{ + OptimisticModeFetcher: mockChainService, + FinalizationFetcher: mockChainService, + Blocker: mockBlockFetcher, } - }) - - t.Run("Bellatrix", func(t *testing.T) { - resetFn := features.InitWithReset(&features.Flags{ - SaveFullExecutionPayloads: true, - }) - defer resetFn() - beaconDB := dbTest.SetupDB(t) - ctx := context.Background() - genBlk, blkContainers := fillDBTestBlocksBellatrix(ctx, t, beaconDB) - canonicalRoots := make(map[[32]byte]bool) - for _, bContr := range blkContainers { - canonicalRoots[bytesutil.ToBytes32(bContr.BlockRoot)] = true - } - headBlock := blkContainers[len(blkContainers)-1] - nextSlot := headBlock.GetBellatrixBlock().Block.Slot + 1 + blk, err := bs.GetBlockV2(ctx, ðpbv2.BlockRequestV2{}) + require.NoError(t, err) - chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetBellatrixBlock()) + v1Block, err := migration.V1Alpha1BeaconBlockCapellaToV2(b.Block) require.NoError(t, err) + bellatrixBlock, ok := blk.Data.Message.(*ethpbv2.SignedBeaconBlockContainer_CapellaBlock) + require.Equal(t, true, ok) + assert.DeepEqual(t, v1Block, bellatrixBlock.CapellaBlock) + assert.Equal(t, ethpbv2.Version_CAPELLA, blk.Version) + }) + t.Run("execution optimistic", func(t *testing.T) { + b := util.NewBeaconBlockBellatrix() + sb, err := blocks.NewSignedBeaconBlock(b) + require.NoError(t, err) + r, err := sb.Block().HashTreeRoot() + require.NoError(t, err) + mockBlockFetcher := &testutil.MockBlocker{BlockToReturn: sb} mockChainService := &mock.ChainService{ - DB: beaconDB, - Block: chainBlk, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - CanonicalRoots: canonicalRoots, - FinalizedRoots: map[[32]byte]bool{}, + OptimisticRoots: map[[32]byte]bool{r: true}, + FinalizedRoots: map[[32]byte]bool{}, } bs := &Server{ - BeaconDB: beaconDB, - ChainInfoFetcher: mockChainService, - HeadFetcher: mockChainService, OptimisticModeFetcher: mockChainService, - ExecutionPayloadReconstructor: &executionTest.EngineClient{ - ExecutionPayloadByBlockHash: map[[32]byte]*enginev1.ExecutionPayload{}, - }, - FinalizationFetcher: mockChainService, + FinalizationFetcher: mockChainService, + Blocker: mockBlockFetcher, } - root, err := genBlk.Block.HashTreeRoot() + blk, err := bs.GetBlockV2(ctx, ðpbv2.BlockRequestV2{}) + require.NoError(t, err) + assert.Equal(t, true, blk.ExecutionOptimistic) + }) + t.Run("finalized", func(t *testing.T) { + b := util.NewBeaconBlock() + sb, err := blocks.NewSignedBeaconBlock(b) require.NoError(t, err) - - tests := []struct { - name string - blockID []byte - want *ethpbalpha.SignedBeaconBlockBellatrix - wantErr bool - }{ - { - name: "slot", - blockID: []byte("30"), - want: blkContainers[30].GetBellatrixBlock(), - }, - { - name: "bad formatting", - blockID: []byte("3bad0"), - wantErr: true, - }, - { - name: "canonical", - blockID: []byte("30"), - want: blkContainers[30].GetBellatrixBlock(), - }, - { - name: "non canonical", - blockID: []byte(fmt.Sprintf("%d", nextSlot)), - wantErr: true, - }, - { - name: "head", - blockID: []byte("head"), - want: headBlock.GetBellatrixBlock(), - }, - { - name: "finalized", - blockID: []byte("finalized"), - want: blkContainers[64].GetBellatrixBlock(), - }, - { - name: "genesis", - blockID: []byte("genesis"), - want: genBlk, - }, - { - name: "genesis root", - blockID: root[:], - want: genBlk, - }, - { - name: "root", - blockID: blkContainers[20].BlockRoot, - want: blkContainers[20].GetBellatrixBlock(), - }, - { - name: "non-existent root", - blockID: bytesutil.PadTo([]byte("hi there"), 32), - wantErr: true, - }, - { - name: "no block", - blockID: []byte("105"), - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - blk, err := bs.GetBlockV2(ctx, ðpbv2.BlockRequestV2{ - BlockId: tt.blockID, - }) - if tt.wantErr { - require.NotEqual(t, err, nil) - return - } - require.NoError(t, err) - - v2Block, err := migration.V1Alpha1BeaconBlockBellatrixToV2(tt.want.Block) - require.NoError(t, err) - - b, ok := blk.Data.Message.(*ethpbv2.SignedBeaconBlockContainer_BellatrixBlock) - require.Equal(t, true, ok) - if !reflect.DeepEqual(b.BellatrixBlock, v2Block) { - t.Error("Expected blocks to equal") - } - assert.Equal(t, ethpbv2.Version_BELLATRIX, blk.Version) - }) - } - }) - - t.Run("Capella", func(t *testing.T) { - resetFn := features.InitWithReset(&features.Flags{ - SaveFullExecutionPayloads: true, - }) - defer resetFn() - beaconDB := dbTest.SetupDB(t) - ctx := context.Background() - - genBlk, blkContainers := fillDBTestBlocksCapella(ctx, t, beaconDB) - canonicalRoots := make(map[[32]byte]bool) - - for _, bContr := range blkContainers { - canonicalRoots[bytesutil.ToBytes32(bContr.BlockRoot)] = true - } - headBlock := blkContainers[len(blkContainers)-1] - nextSlot := headBlock.GetCapellaBlock().Block.Slot + 1 - - chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetCapellaBlock()) - require.NoError(t, err) - mockChainService := &mock.ChainService{ - DB: beaconDB, - Block: chainBlk, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - CanonicalRoots: canonicalRoots, - FinalizedRoots: map[[32]byte]bool{}, - } - bs := &Server{ - BeaconDB: beaconDB, - ChainInfoFetcher: mockChainService, - HeadFetcher: mockChainService, - OptimisticModeFetcher: mockChainService, - ExecutionPayloadReconstructor: &executionTest.EngineClient{ - ExecutionPayloadByBlockHash: map[[32]byte]*enginev1.ExecutionPayload{}, - }, - FinalizationFetcher: mockChainService, - } - - root, err := genBlk.Block.HashTreeRoot() - require.NoError(t, err) - - tests := []struct { - name string - blockID []byte - want *ethpbalpha.SignedBeaconBlockCapella - wantErr bool - }{ - { - name: "slot", - blockID: []byte("30"), - want: blkContainers[30].GetCapellaBlock(), - }, - { - name: "bad formatting", - blockID: []byte("3bad0"), - wantErr: true, - }, - { - name: "canonical", - blockID: []byte("30"), - want: blkContainers[30].GetCapellaBlock(), - }, - { - name: "non canonical", - blockID: []byte(fmt.Sprintf("%d", nextSlot)), - wantErr: true, - }, - { - name: "head", - blockID: []byte("head"), - want: headBlock.GetCapellaBlock(), - }, - { - name: "finalized", - blockID: []byte("finalized"), - want: blkContainers[64].GetCapellaBlock(), - }, - { - name: "genesis", - blockID: []byte("genesis"), - want: genBlk, - }, - { - name: "genesis root", - blockID: root[:], - want: genBlk, - }, - { - name: "root", - blockID: blkContainers[20].BlockRoot, - want: blkContainers[20].GetCapellaBlock(), - }, - { - name: "non-existent root", - blockID: bytesutil.PadTo([]byte("hi there"), 32), - wantErr: true, - }, - { - name: "no block", - blockID: []byte("105"), - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - blk, err := bs.GetBlockV2(ctx, ðpbv2.BlockRequestV2{ - BlockId: tt.blockID, - }) - if tt.wantErr { - require.NotEqual(t, err, nil) - return - } - require.NoError(t, err) - - v2Block, err := migration.V1Alpha1BeaconBlockCapellaToV2(tt.want.Block) - require.NoError(t, err) - - b, ok := blk.Data.Message.(*ethpbv2.SignedBeaconBlockContainer_CapellaBlock) - require.Equal(t, true, ok) - if !reflect.DeepEqual(b.CapellaBlock, v2Block) { - t.Error("Expected blocks to equal") - } - assert.Equal(t, ethpbv2.Version_CAPELLA, blk.Version) - }) - } - }) - - t.Run("execution optimistic", func(t *testing.T) { - beaconDB := dbTest.SetupDB(t) - ctx := context.Background() - - _, blkContainers := fillDBTestBlocksBellatrix(ctx, t, beaconDB) - headBlock := blkContainers[len(blkContainers)-1] - - chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetBellatrixBlock()) - require.NoError(t, err) - mockChainService := &mock.ChainService{ - DB: beaconDB, - Block: chainBlk, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - Optimistic: true, - FinalizedRoots: map[[32]byte]bool{}, - OptimisticRoots: map[[32]byte]bool{ - bytesutil.ToBytes32(headBlock.BlockRoot): true, - }, - } - bs := &Server{ - BeaconDB: beaconDB, - ChainInfoFetcher: mockChainService, - HeadFetcher: mockChainService, - OptimisticModeFetcher: mockChainService, - FinalizationFetcher: mockChainService, - } - - blk, err := bs.GetBlockV2(ctx, ðpbv2.BlockRequestV2{ - BlockId: []byte("head"), - }) - require.NoError(t, err) - assert.Equal(t, true, blk.ExecutionOptimistic) - }) - - t.Run("finalized", func(t *testing.T) { - beaconDB := dbTest.SetupDB(t) - ctx := context.Background() - - _, blkContainers := fillDBTestBlocks(ctx, t, beaconDB) - headBlock := blkContainers[len(blkContainers)-1] - - chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetPhase0Block()) - require.NoError(t, err) - mockChainService := &mock.ChainService{ - DB: beaconDB, - Block: chainBlk, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - Optimistic: true, - FinalizedRoots: map[[32]byte]bool{ - bytesutil.ToBytes32(blkContainers[32].BlockRoot): true, - bytesutil.ToBytes32(blkContainers[64].BlockRoot): false, - }, - } - bs := &Server{ - BeaconDB: beaconDB, - ChainInfoFetcher: mockChainService, - HeadFetcher: mockChainService, - OptimisticModeFetcher: mockChainService, - FinalizationFetcher: mockChainService, - } + r, err := sb.Block().HashTreeRoot() + require.NoError(t, err) + mockBlockFetcher := &testutil.MockBlocker{BlockToReturn: sb} t.Run("true", func(t *testing.T) { - blk, err := bs.GetBlockV2(ctx, ðpbv2.BlockRequestV2{ - BlockId: []byte("32"), - }) + mockChainService := &mock.ChainService{FinalizedRoots: map[[32]byte]bool{r: true}} + bs := &Server{ + OptimisticModeFetcher: mockChainService, + FinalizationFetcher: mockChainService, + Blocker: mockBlockFetcher, + } + + header, err := bs.GetBlockV2(ctx, ðpbv2.BlockRequestV2{BlockId: r[:]}) require.NoError(t, err) - assert.Equal(t, true, blk.Finalized) + assert.Equal(t, true, header.Finalized) }) t.Run("false", func(t *testing.T) { - blk, err := bs.GetBlockV2(ctx, ðpbv2.BlockRequestV2{ - BlockId: []byte("64"), - }) + mockChainService := &mock.ChainService{FinalizedRoots: map[[32]byte]bool{r: false}} + bs := &Server{ + OptimisticModeFetcher: mockChainService, + FinalizationFetcher: mockChainService, + Blocker: mockBlockFetcher, + } + + resp, err := bs.GetBlockV2(ctx, ðpbv2.BlockRequestV2{BlockId: r[:]}) require.NoError(t, err) - assert.Equal(t, false, blk.Finalized) + assert.Equal(t, false, resp.Finalized) }) }) } func TestServer_GetBlockSSZ(t *testing.T) { - beaconDB := dbTest.SetupDB(t) ctx := context.Background() - - _, blkContainers := fillDBTestBlocks(ctx, t, beaconDB) - headBlock := blkContainers[len(blkContainers)-1] - - b2 := util.NewBeaconBlock() - b2.Block.Slot = 30 - b2.Block.ParentRoot = bytesutil.PadTo([]byte{1}, 32) - util.SaveBlock(t, ctx, beaconDB, b2) - - wsb, err := blocks.NewSignedBeaconBlock(headBlock.Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block) + b := util.NewBeaconBlock() + b.Block.Slot = 123 + sb, err := blocks.NewSignedBeaconBlock(b) require.NoError(t, err) - bs := &Server{ - BeaconDB: beaconDB, - ChainInfoFetcher: &mock.ChainService{ - DB: beaconDB, - Block: wsb, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - }, + Blocker: &testutil.MockBlocker{BlockToReturn: sb}, } - blks, err := beaconDB.BlocksBySlot(ctx, 30) - require.Equal(t, true, len(blks) > 0) - require.NoError(t, err) - sszBlock, err := blks[0].MarshalSSZ() - require.NoError(t, err) - - resp, err := bs.GetBlockSSZ(ctx, ðpbv1.BlockRequest{BlockId: []byte("30")}) + resp, err := bs.GetBlockSSZ(ctx, ðpbv1.BlockRequest{}) require.NoError(t, err) assert.NotNil(t, resp) + sszBlock, err := b.MarshalSSZ() + require.NoError(t, err) assert.DeepEqual(t, sszBlock, resp.Data) } func TestServer_GetBlockSSZV2(t *testing.T) { - t.Run("Phase 0", func(t *testing.T) { - beaconDB := dbTest.SetupDB(t) - ctx := context.Background() + ctx := context.Background() - _, blkContainers := fillDBTestBlocks(ctx, t, beaconDB) - headBlock := blkContainers[len(blkContainers)-1] - wsb, err := blocks.NewSignedBeaconBlock(headBlock.Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block) + t.Run("Phase 0", func(t *testing.T) { + b := util.NewBeaconBlock() + b.Block.Slot = 123 + sb, err := blocks.NewSignedBeaconBlock(b) require.NoError(t, err) + mockChainService := &mock.ChainService{ - DB: beaconDB, - Block: wsb, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - FinalizedRoots: map[[32]byte]bool{}, + FinalizedRoots: map[[32]byte]bool{}, } bs := &Server{ - BeaconDB: beaconDB, - ChainInfoFetcher: mockChainService, FinalizationFetcher: mockChainService, + Blocker: &testutil.MockBlocker{BlockToReturn: sb}, } - blks, err := beaconDB.BlocksBySlot(ctx, 30) - require.Equal(t, true, len(blks) > 0) - require.NoError(t, err) - sszBlock, err := blks[0].MarshalSSZ() - require.NoError(t, err) - - resp, err := bs.GetBlockSSZV2(ctx, ðpbv2.BlockRequestV2{BlockId: []byte("30")}) + resp, err := bs.GetBlockSSZV2(ctx, ðpbv2.BlockRequestV2{}) require.NoError(t, err) assert.NotNil(t, resp) + sszBlock, err := b.MarshalSSZ() + require.NoError(t, err) assert.DeepEqual(t, sszBlock, resp.Data) assert.Equal(t, ethpbv2.Version_PHASE0, resp.Version) }) - t.Run("Altair", func(t *testing.T) { - beaconDB := dbTest.SetupDB(t) - ctx := context.Background() - - _, blkContainers := fillDBTestBlocksAltair(ctx, t, beaconDB) - headBlock := blkContainers[len(blkContainers)-1] - chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetAltairBlock()) + b := util.NewBeaconBlockAltair() + b.Block.Slot = 123 + sb, err := blocks.NewSignedBeaconBlock(b) require.NoError(t, err) + mockChainService := &mock.ChainService{ - DB: beaconDB, - Block: chainBlk, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - FinalizedRoots: map[[32]byte]bool{}, + FinalizedRoots: map[[32]byte]bool{}, } bs := &Server{ - BeaconDB: beaconDB, - ChainInfoFetcher: mockChainService, FinalizationFetcher: mockChainService, + Blocker: &testutil.MockBlocker{BlockToReturn: sb}, } - blks, err := beaconDB.BlocksBySlot(ctx, 30) - require.Equal(t, true, len(blks) > 0) - require.NoError(t, err) - sszBlock, err := blks[0].MarshalSSZ() - require.NoError(t, err) - - resp, err := bs.GetBlockSSZV2(ctx, ðpbv2.BlockRequestV2{BlockId: []byte("30")}) + resp, err := bs.GetBlockSSZV2(ctx, ðpbv2.BlockRequestV2{}) require.NoError(t, err) assert.NotNil(t, resp) + sszBlock, err := b.MarshalSSZ() + require.NoError(t, err) assert.DeepEqual(t, sszBlock, resp.Data) assert.Equal(t, ethpbv2.Version_ALTAIR, resp.Version) }) - t.Run("Bellatrix", func(t *testing.T) { - resetFn := features.InitWithReset(&features.Flags{ - SaveFullExecutionPayloads: true, - }) - defer resetFn() - beaconDB := dbTest.SetupDB(t) - ctx := context.Background() - - _, blkContainers := fillDBTestBlocksBellatrix(ctx, t, beaconDB) - headBlock := blkContainers[len(blkContainers)-1] - chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetBellatrixBlock()) - require.NoError(t, err) - mockChainService := &mock.ChainService{ - DB: beaconDB, - Block: chainBlk, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - FinalizedRoots: map[[32]byte]bool{}, - } - bs := &Server{ - BeaconDB: beaconDB, - ChainInfoFetcher: mockChainService, - OptimisticModeFetcher: mockChainService, - FinalizationFetcher: mockChainService, - } - - blks, err := beaconDB.BlocksBySlot(ctx, 30) - require.Equal(t, true, len(blks) > 0) - require.NoError(t, err) - sszBlock, err := blks[0].MarshalSSZ() - require.NoError(t, err) - - resp, err := bs.GetBlockSSZV2(ctx, ðpbv2.BlockRequestV2{BlockId: []byte("30")}) - require.NoError(t, err) - assert.NotNil(t, resp) - assert.DeepEqual(t, sszBlock, resp.Data) - assert.Equal(t, ethpbv2.Version_BELLATRIX, resp.Version) - }) - - t.Run("Capella", func(t *testing.T) { - resetFn := features.InitWithReset(&features.Flags{ - SaveFullExecutionPayloads: true, - }) - defer resetFn() - beaconDB := dbTest.SetupDB(t) - ctx := context.Background() - - _, blkContainers := fillDBTestBlocksCapella(ctx, t, beaconDB) - headBlock := blkContainers[len(blkContainers)-1] - chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetCapellaBlock()) - require.NoError(t, err) - mockChainService := &mock.ChainService{ - DB: beaconDB, - Block: chainBlk, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - FinalizedRoots: map[[32]byte]bool{}, - } - bs := &Server{ - BeaconDB: beaconDB, - ChainInfoFetcher: mockChainService, - OptimisticModeFetcher: mockChainService, - FinalizationFetcher: mockChainService, - } - - blks, err := beaconDB.BlocksBySlot(ctx, 30) - require.Equal(t, true, len(blks) > 0) - require.NoError(t, err) - sszBlock, err := blks[0].MarshalSSZ() - require.NoError(t, err) - - resp, err := bs.GetBlockSSZV2(ctx, ðpbv2.BlockRequestV2{BlockId: []byte("30")}) - require.NoError(t, err) - assert.NotNil(t, resp) - assert.DeepEqual(t, sszBlock, resp.Data) - assert.Equal(t, ethpbv2.Version_CAPELLA, resp.Version) - }) - - t.Run("execution optimistic", func(t *testing.T) { - beaconDB := dbTest.SetupDB(t) - ctx := context.Background() - - _, blkContainers := fillDBTestBlocksBellatrix(ctx, t, beaconDB) - headBlock := blkContainers[len(blkContainers)-1] - - chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetBellatrixBlock()) - require.NoError(t, err) - mockChainService := &mock.ChainService{ - DB: beaconDB, - Block: chainBlk, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - Optimistic: true, - FinalizedRoots: map[[32]byte]bool{}, - OptimisticRoots: map[[32]byte]bool{ - bytesutil.ToBytes32(headBlock.BlockRoot): true, - }, - } - bs := &Server{ - BeaconDB: beaconDB, - ChainInfoFetcher: mockChainService, - HeadFetcher: mockChainService, - OptimisticModeFetcher: mockChainService, - FinalizationFetcher: mockChainService, - } - - blk, err := bs.GetBlockSSZV2(ctx, ðpbv2.BlockRequestV2{ - BlockId: []byte("head"), - }) - require.NoError(t, err) - assert.Equal(t, true, blk.ExecutionOptimistic) - }) - - t.Run("finalized", func(t *testing.T) { - beaconDB := dbTest.SetupDB(t) - ctx := context.Background() - - _, blkContainers := fillDBTestBlocks(ctx, t, beaconDB) - headBlock := blkContainers[len(blkContainers)-1] - - chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetPhase0Block()) - require.NoError(t, err) - mockChainService := &mock.ChainService{ - DB: beaconDB, - Block: chainBlk, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - Optimistic: true, - FinalizedRoots: map[[32]byte]bool{ - bytesutil.ToBytes32(blkContainers[32].BlockRoot): true, - bytesutil.ToBytes32(blkContainers[64].BlockRoot): false, - }, - } - bs := &Server{ - BeaconDB: beaconDB, - ChainInfoFetcher: mockChainService, - HeadFetcher: mockChainService, - OptimisticModeFetcher: mockChainService, - FinalizationFetcher: mockChainService, - } - - t.Run("true", func(t *testing.T) { - blk, err := bs.GetBlockV2(ctx, ðpbv2.BlockRequestV2{ - BlockId: []byte("32"), - }) - require.NoError(t, err) - assert.Equal(t, true, blk.Finalized) - }) - t.Run("false", func(t *testing.T) { - blk, err := bs.GetBlockV2(ctx, ðpbv2.BlockRequestV2{ - BlockId: []byte("64"), - }) - require.NoError(t, err) - assert.Equal(t, false, blk.Finalized) - }) - }) -} - -func TestServer_GetBlockRoot(t *testing.T) { - beaconDB := dbTest.SetupDB(t) - ctx := context.Background() - - genBlk, blkContainers := fillDBTestBlocks(ctx, t, beaconDB) - headBlock := blkContainers[len(blkContainers)-1] - - t.Run("get root", func(t *testing.T) { - wsb, err := blocks.NewSignedBeaconBlock(headBlock.Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block) - require.NoError(t, err) - mockChainFetcher := &mock.ChainService{ - DB: beaconDB, - Block: wsb, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - FinalizedRoots: map[[32]byte]bool{}, - } - bs := &Server{ - BeaconDB: beaconDB, - ChainInfoFetcher: mockChainFetcher, - HeadFetcher: mockChainFetcher, - OptimisticModeFetcher: mockChainFetcher, - FinalizationFetcher: mockChainFetcher, - } - - root, err := genBlk.Block.HashTreeRoot() - require.NoError(t, err) - - tests := []struct { - name string - blockID []byte - want []byte - wantErr bool - }{ - { - name: "bad formatting", - blockID: []byte("3bad0"), - wantErr: true, - }, - { - name: "canonical slot", - blockID: []byte("30"), - want: blkContainers[30].BlockRoot, - }, - { - name: "head", - blockID: []byte("head"), - want: headBlock.BlockRoot, - }, - { - name: "finalized", - blockID: []byte("finalized"), - want: blkContainers[64].BlockRoot, - }, - { - name: "genesis", - blockID: []byte("genesis"), - want: root[:], - }, - { - name: "genesis root", - blockID: root[:], - want: root[:], - }, - { - name: "root", - blockID: blkContainers[20].BlockRoot, - want: blkContainers[20].BlockRoot, - }, - { - name: "non-existent root", - blockID: bytesutil.PadTo([]byte("hi there"), 32), - wantErr: true, - }, - { - name: "slot", - blockID: []byte("40"), - want: blkContainers[40].BlockRoot, - }, - { - name: "no block", - blockID: []byte("105"), - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - blockRootResp, err := bs.GetBlockRoot(ctx, ðpbv1.BlockRequest{ - BlockId: tt.blockID, - }) - if tt.wantErr { - require.NotEqual(t, err, nil) - return - } - require.NoError(t, err) - assert.DeepEqual(t, tt.want, blockRootResp.Data.Root) - }) - } - }) - - t.Run("execution optimistic", func(t *testing.T) { - wsb, err := blocks.NewSignedBeaconBlock(headBlock.Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block) - require.NoError(t, err) - mockChainFetcher := &mock.ChainService{ - DB: beaconDB, - Block: wsb, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - Optimistic: true, - FinalizedRoots: map[[32]byte]bool{}, - OptimisticRoots: map[[32]byte]bool{ - bytesutil.ToBytes32(headBlock.BlockRoot): true, - }, - } - bs := &Server{ - BeaconDB: beaconDB, - ChainInfoFetcher: mockChainFetcher, - HeadFetcher: mockChainFetcher, - OptimisticModeFetcher: mockChainFetcher, - FinalizationFetcher: mockChainFetcher, - } - blockRootResp, err := bs.GetBlockRoot(ctx, ðpbv1.BlockRequest{ - BlockId: []byte("head"), - }) - require.NoError(t, err) - assert.Equal(t, true, blockRootResp.ExecutionOptimistic) - }) - - t.Run("finalized", func(t *testing.T) { - wsb, err := blocks.NewSignedBeaconBlock(headBlock.Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block) + b := util.NewBeaconBlockBellatrix() + b.Block.Slot = 123 + sb, err := blocks.NewSignedBeaconBlock(b) require.NoError(t, err) - mockChainFetcher := &mock.ChainService{ - DB: beaconDB, - Block: wsb, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - Optimistic: true, - FinalizedRoots: map[[32]byte]bool{ - bytesutil.ToBytes32(blkContainers[32].BlockRoot): true, - bytesutil.ToBytes32(blkContainers[64].BlockRoot): false, - }, - } - bs := &Server{ - BeaconDB: beaconDB, - ChainInfoFetcher: mockChainFetcher, - HeadFetcher: mockChainFetcher, - OptimisticModeFetcher: mockChainFetcher, - FinalizationFetcher: mockChainFetcher, - } - - t.Run("true", func(t *testing.T) { - blockRootResp, err := bs.GetBlockRoot(ctx, ðpbv1.BlockRequest{ - BlockId: []byte("32"), - }) - require.NoError(t, err) - assert.Equal(t, true, blockRootResp.Finalized) - }) - t.Run("false", func(t *testing.T) { - blockRootResp, err := bs.GetBlockRoot(ctx, ðpbv1.BlockRequest{ - BlockId: []byte("64"), - }) - require.NoError(t, err) - assert.Equal(t, false, blockRootResp.Finalized) - }) - }) -} - -func TestServer_ListBlockAttestations(t *testing.T) { - t.Run("Phase 0", func(t *testing.T) { - beaconDB := dbTest.SetupDB(t) - ctx := context.Background() - _, blkContainers := fillDBTestBlocks(ctx, t, beaconDB) - headBlock := blkContainers[len(blkContainers)-1] - wsb, err := blocks.NewSignedBeaconBlock(headBlock.Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block) - require.NoError(t, err) mockChainService := &mock.ChainService{ - DB: beaconDB, - Block: wsb, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - FinalizedRoots: map[[32]byte]bool{}, + FinalizedRoots: map[[32]byte]bool{}, } bs := &Server{ - BeaconDB: beaconDB, - ChainInfoFetcher: mockChainService, - HeadFetcher: mockChainService, OptimisticModeFetcher: mockChainService, FinalizationFetcher: mockChainService, + Blocker: &testutil.MockBlocker{BlockToReturn: sb}, } - genBlk, blkContainers := fillDBTestBlocks(ctx, t, beaconDB) - root, err := genBlk.Block.HashTreeRoot() - require.NoError(t, err) - - tests := []struct { - name string - blockID []byte - want *ethpbalpha.SignedBeaconBlock - wantErr bool - }{ - { - name: "slot", - blockID: []byte("30"), - want: blkContainers[30].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block, - }, - { - name: "bad formatting", - blockID: []byte("3bad0"), - wantErr: true, - }, - { - name: "head", - blockID: []byte("head"), - want: headBlock.Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block, - }, - { - name: "finalized", - blockID: []byte("finalized"), - want: blkContainers[64].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block, - }, - { - name: "genesis", - blockID: []byte("genesis"), - want: genBlk, - }, - { - name: "genesis root", - blockID: root[:], - want: genBlk, - }, - { - name: "root", - blockID: blkContainers[20].BlockRoot, - want: blkContainers[20].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block, - }, - { - name: "non-existent root", - blockID: bytesutil.PadTo([]byte("hi there"), 32), - wantErr: true, - }, - { - name: "slot", - blockID: []byte("40"), - want: blkContainers[40].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block, - }, - { - name: "no block", - blockID: []byte("105"), - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - blk, err := bs.ListBlockAttestations(ctx, ðpbv1.BlockRequest{ - BlockId: tt.blockID, - }) - if tt.wantErr { - require.NotEqual(t, err, nil) - return - } - require.NoError(t, err) - - v1Block, err := migration.V1Alpha1ToV1SignedBlock(tt.want) - require.NoError(t, err) - blkAtts := blk.Data - if len(blkAtts) == 0 { - blkAtts = nil - } - if !reflect.DeepEqual(blkAtts, v1Block.Block.Body.Attestations) { - t.Error("Expected attestations to equal") - } - }) - } - }) - - t.Run("Altair", func(t *testing.T) { - beaconDB := dbTest.SetupDB(t) - ctx := context.Background() - - _, blkContainers := fillDBTestBlocksAltair(ctx, t, beaconDB) - headBlock := blkContainers[len(blkContainers)-1] - blk, err := blocks.NewSignedBeaconBlock(headBlock.Block.(*ethpbalpha.BeaconBlockContainer_AltairBlock).AltairBlock) - require.NoError(t, err) - mockChainService := &mock.ChainService{ - DB: beaconDB, - Block: blk, - Root: headBlock.BlockRoot, - FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, - FinalizedRoots: map[[32]byte]bool{}, - } - bs := &Server{ - BeaconDB: beaconDB, - ChainInfoFetcher: mockChainService, - HeadFetcher: mockChainService, - OptimisticModeFetcher: mockChainService, - FinalizationFetcher: mockChainService, - } - - genBlk, blkContainers := fillDBTestBlocksAltair(ctx, t, beaconDB) - root, err := genBlk.Block.HashTreeRoot() - require.NoError(t, err) - - tests := []struct { - name string - blockID []byte - want *ethpbalpha.SignedBeaconBlockAltair - wantErr bool - }{ - { - name: "slot", - blockID: []byte("30"), - want: blkContainers[30].Block.(*ethpbalpha.BeaconBlockContainer_AltairBlock).AltairBlock, - }, - { - name: "bad formatting", - blockID: []byte("3bad0"), - wantErr: true, - }, - { - name: "head", - blockID: []byte("head"), - want: headBlock.Block.(*ethpbalpha.BeaconBlockContainer_AltairBlock).AltairBlock, - }, - { - name: "finalized", - blockID: []byte("finalized"), - want: blkContainers[64].Block.(*ethpbalpha.BeaconBlockContainer_AltairBlock).AltairBlock, - }, - { - name: "genesis", - blockID: []byte("genesis"), - want: genBlk, - }, - { - name: "genesis root", - blockID: root[:], - want: genBlk, - }, - { - name: "root", - blockID: blkContainers[20].BlockRoot, - want: blkContainers[20].Block.(*ethpbalpha.BeaconBlockContainer_AltairBlock).AltairBlock, - }, - { - name: "non-existent root", - blockID: bytesutil.PadTo([]byte("hi there"), 32), - wantErr: true, - }, - { - name: "slot", - blockID: []byte("40"), - want: blkContainers[40].Block.(*ethpbalpha.BeaconBlockContainer_AltairBlock).AltairBlock, - }, - { - name: "no block", - blockID: []byte("105"), - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - blk, err := bs.ListBlockAttestations(ctx, ðpbv1.BlockRequest{ - BlockId: tt.blockID, - }) - if tt.wantErr { - require.NotEqual(t, err, nil) - return - } - require.NoError(t, err) - - v1Block, err := migration.V1Alpha1BeaconBlockAltairToV2(tt.want.Block) - require.NoError(t, err) + resp, err := bs.GetBlockSSZV2(ctx, ðpbv2.BlockRequestV2{}) + require.NoError(t, err) + assert.NotNil(t, resp) + sszBlock, err := b.MarshalSSZ() + require.NoError(t, err) + assert.DeepEqual(t, sszBlock, resp.Data) + assert.Equal(t, ethpbv2.Version_BELLATRIX, resp.Version) + }) + t.Run("Capella", func(t *testing.T) { + b := util.NewBeaconBlockCapella() + b.Block.Slot = 123 + sb, err := blocks.NewSignedBeaconBlock(b) + require.NoError(t, err) - blkAtts := blk.Data - if len(blkAtts) == 0 { - blkAtts = nil - } - if !reflect.DeepEqual(blkAtts, v1Block.Body.Attestations) { - t.Error("Expected attestations to equal") - } - }) + mockChainService := &mock.ChainService{ + FinalizedRoots: map[[32]byte]bool{}, + } + bs := &Server{ + OptimisticModeFetcher: mockChainService, + FinalizationFetcher: mockChainService, + Blocker: &testutil.MockBlocker{BlockToReturn: sb}, } + + resp, err := bs.GetBlockSSZV2(ctx, ðpbv2.BlockRequestV2{}) + require.NoError(t, err) + assert.NotNil(t, resp) + sszBlock, err := b.MarshalSSZ() + require.NoError(t, err) + assert.DeepEqual(t, sszBlock, resp.Data) + assert.Equal(t, ethpbv2.Version_CAPELLA, resp.Version) }) + t.Run("execution optimistic", func(t *testing.T) { + b := util.NewBeaconBlockBellatrix() + sb, err := blocks.NewSignedBeaconBlock(b) + require.NoError(t, err) + r, err := sb.Block().HashTreeRoot() + require.NoError(t, err) - t.Run("Bellatrix", func(t *testing.T) { - beaconDB := dbTest.SetupDB(t) - ctx := context.Background() + mockChainService := &mock.ChainService{ + OptimisticRoots: map[[32]byte]bool{r: true}, + FinalizedRoots: map[[32]byte]bool{}, + } + bs := &Server{ + OptimisticModeFetcher: mockChainService, + FinalizationFetcher: mockChainService, + Blocker: &testutil.MockBlocker{BlockToReturn: sb}, + } - _, blkContainers := fillDBTestBlocksBellatrix(ctx, t, beaconDB) - headBlock := blkContainers[len(blkContainers)-1] - blk, err := blocks.NewSignedBeaconBlock(headBlock.Block.(*ethpbalpha.BeaconBlockContainer_BellatrixBlock).BellatrixBlock) + resp, err := bs.GetBlockSSZV2(ctx, ðpbv2.BlockRequestV2{}) require.NoError(t, err) - mockChainService := &mock.ChainService{ + assert.Equal(t, true, resp.ExecutionOptimistic) + }) + t.Run("finalized", func(t *testing.T) { + b := util.NewBeaconBlock() + sb, err := blocks.NewSignedBeaconBlock(b) + require.NoError(t, err) + r, err := sb.Block().HashTreeRoot() + require.NoError(t, err) + mockBlockFetcher := &testutil.MockBlocker{BlockToReturn: sb} + + t.Run("true", func(t *testing.T) { + mockChainService := &mock.ChainService{FinalizedRoots: map[[32]byte]bool{r: true}} + bs := &Server{ + OptimisticModeFetcher: mockChainService, + FinalizationFetcher: mockChainService, + Blocker: mockBlockFetcher, + } + + header, err := bs.GetBlockSSZV2(ctx, ðpbv2.BlockRequestV2{BlockId: r[:]}) + require.NoError(t, err) + assert.Equal(t, true, header.Finalized) + }) + t.Run("false", func(t *testing.T) { + mockChainService := &mock.ChainService{FinalizedRoots: map[[32]byte]bool{r: false}} + bs := &Server{ + OptimisticModeFetcher: mockChainService, + FinalizationFetcher: mockChainService, + Blocker: mockBlockFetcher, + } + + resp, err := bs.GetBlockSSZV2(ctx, ðpbv2.BlockRequestV2{BlockId: r[:]}) + require.NoError(t, err) + assert.Equal(t, false, resp.Finalized) + }) + }) +} + +func TestServer_GetBlockRoot(t *testing.T) { + beaconDB := dbTest.SetupDB(t) + ctx := context.Background() + + genBlk, blkContainers := fillDBTestBlocks(ctx, t, beaconDB) + headBlock := blkContainers[len(blkContainers)-1] + + t.Run("get root", func(t *testing.T) { + wsb, err := blocks.NewSignedBeaconBlock(headBlock.Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block) + require.NoError(t, err) + mockChainFetcher := &mock.ChainService{ DB: beaconDB, - Block: blk, + Block: wsb, Root: headBlock.BlockRoot, FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, FinalizedRoots: map[[32]byte]bool{}, } bs := &Server{ BeaconDB: beaconDB, - ChainInfoFetcher: mockChainService, - HeadFetcher: mockChainService, - OptimisticModeFetcher: mockChainService, - FinalizationFetcher: mockChainService, + ChainInfoFetcher: mockChainFetcher, + HeadFetcher: mockChainFetcher, + OptimisticModeFetcher: mockChainFetcher, + FinalizationFetcher: mockChainFetcher, } - genBlk, blkContainers := fillDBTestBlocksBellatrix(ctx, t, beaconDB) root, err := genBlk.Block.HashTreeRoot() require.NoError(t, err) tests := []struct { name string blockID []byte - want *ethpbalpha.SignedBeaconBlockBellatrix + want []byte wantErr bool }{ - { - name: "slot", - blockID: []byte("30"), - want: blkContainers[30].Block.(*ethpbalpha.BeaconBlockContainer_BellatrixBlock).BellatrixBlock, - }, { name: "bad formatting", blockID: []byte("3bad0"), wantErr: true, }, + { + name: "canonical slot", + blockID: []byte("30"), + want: blkContainers[30].BlockRoot, + }, { name: "head", blockID: []byte("head"), - want: headBlock.Block.(*ethpbalpha.BeaconBlockContainer_BellatrixBlock).BellatrixBlock, + want: headBlock.BlockRoot, }, { name: "finalized", blockID: []byte("finalized"), - want: blkContainers[64].Block.(*ethpbalpha.BeaconBlockContainer_BellatrixBlock).BellatrixBlock, + want: blkContainers[64].BlockRoot, }, { name: "genesis", blockID: []byte("genesis"), - want: genBlk, + want: root[:], }, { name: "genesis root", blockID: root[:], - want: genBlk, + want: root[:], }, { name: "root", blockID: blkContainers[20].BlockRoot, - want: blkContainers[20].Block.(*ethpbalpha.BeaconBlockContainer_BellatrixBlock).BellatrixBlock, + want: blkContainers[20].BlockRoot, }, { name: "non-existent root", @@ -2461,7 +1090,7 @@ func TestServer_ListBlockAttestations(t *testing.T) { { name: "slot", blockID: []byte("40"), - want: blkContainers[40].Block.(*ethpbalpha.BeaconBlockContainer_BellatrixBlock).BellatrixBlock, + want: blkContainers[40].BlockRoot, }, { name: "no block", @@ -2471,7 +1100,7 @@ func TestServer_ListBlockAttestations(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - blk, err := bs.ListBlockAttestations(ctx, ðpbv1.BlockRequest{ + blockRootResp, err := bs.GetBlockRoot(ctx, ðpbv1.BlockRequest{ BlockId: tt.blockID, }) if tt.wantErr { @@ -2479,32 +1108,17 @@ func TestServer_ListBlockAttestations(t *testing.T) { return } require.NoError(t, err) - - v1Block, err := migration.V1Alpha1BeaconBlockBellatrixToV2(tt.want.Block) - require.NoError(t, err) - - blkAtts := blk.Data - if len(blkAtts) == 0 { - blkAtts = nil - } - if !reflect.DeepEqual(blkAtts, v1Block.Body.Attestations) { - t.Error("Expected attestations to equal") - } + assert.DeepEqual(t, tt.want, blockRootResp.Data.Root) }) } }) t.Run("execution optimistic", func(t *testing.T) { - beaconDB := dbTest.SetupDB(t) - ctx := context.Background() - - _, blkContainers := fillDBTestBlocksBellatrix(ctx, t, beaconDB) - headBlock := blkContainers[len(blkContainers)-1] - blk, err := blocks.NewSignedBeaconBlock(headBlock.Block.(*ethpbalpha.BeaconBlockContainer_BellatrixBlock).BellatrixBlock) + wsb, err := blocks.NewSignedBeaconBlock(headBlock.Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block) require.NoError(t, err) - mockChainService := &mock.ChainService{ + mockChainFetcher := &mock.ChainService{ DB: beaconDB, - Block: blk, + Block: wsb, Root: headBlock.BlockRoot, FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, Optimistic: true, @@ -2515,31 +1129,27 @@ func TestServer_ListBlockAttestations(t *testing.T) { } bs := &Server{ BeaconDB: beaconDB, - ChainInfoFetcher: mockChainService, - HeadFetcher: mockChainService, - OptimisticModeFetcher: mockChainService, - FinalizationFetcher: mockChainService, + ChainInfoFetcher: mockChainFetcher, + HeadFetcher: mockChainFetcher, + OptimisticModeFetcher: mockChainFetcher, + FinalizationFetcher: mockChainFetcher, } - resp, err := bs.ListBlockAttestations(ctx, ðpbv1.BlockRequest{ + blockRootResp, err := bs.GetBlockRoot(ctx, ðpbv1.BlockRequest{ BlockId: []byte("head"), }) require.NoError(t, err) - assert.Equal(t, true, resp.ExecutionOptimistic) + assert.Equal(t, true, blockRootResp.ExecutionOptimistic) }) t.Run("finalized", func(t *testing.T) { - beaconDB := dbTest.SetupDB(t) - ctx := context.Background() - - _, blkContainers := fillDBTestBlocks(ctx, t, beaconDB) - headBlock := blkContainers[len(blkContainers)-1] - blk, err := blocks.NewSignedBeaconBlock(headBlock.Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block) + wsb, err := blocks.NewSignedBeaconBlock(headBlock.Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block) require.NoError(t, err) - mockChainService := &mock.ChainService{ + mockChainFetcher := &mock.ChainService{ DB: beaconDB, - Block: blk, + Block: wsb, Root: headBlock.BlockRoot, FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, + Optimistic: true, FinalizedRoots: map[[32]byte]bool{ bytesutil.ToBytes32(blkContainers[32].BlockRoot): true, bytesutil.ToBytes32(blkContainers[64].BlockRoot): false, @@ -2547,24 +1157,311 @@ func TestServer_ListBlockAttestations(t *testing.T) { } bs := &Server{ BeaconDB: beaconDB, - ChainInfoFetcher: mockChainService, - HeadFetcher: mockChainService, - OptimisticModeFetcher: mockChainService, - FinalizationFetcher: mockChainService, + ChainInfoFetcher: mockChainFetcher, + HeadFetcher: mockChainFetcher, + OptimisticModeFetcher: mockChainFetcher, + FinalizationFetcher: mockChainFetcher, } t.Run("true", func(t *testing.T) { - resp, err := bs.ListBlockAttestations(ctx, ðpbv1.BlockRequest{ + blockRootResp, err := bs.GetBlockRoot(ctx, ðpbv1.BlockRequest{ BlockId: []byte("32"), }) require.NoError(t, err) - assert.Equal(t, true, resp.Finalized) + assert.Equal(t, true, blockRootResp.Finalized) }) t.Run("false", func(t *testing.T) { - resp, err := bs.ListBlockAttestations(ctx, ðpbv1.BlockRequest{ + blockRootResp, err := bs.GetBlockRoot(ctx, ðpbv1.BlockRequest{ BlockId: []byte("64"), }) require.NoError(t, err) + assert.Equal(t, false, blockRootResp.Finalized) + }) + }) +} + +func TestServer_ListBlockAttestations(t *testing.T) { + ctx := context.Background() + + t.Run("Phase 0", func(t *testing.T) { + b := util.NewBeaconBlock() + b.Block.Body.Attestations = []*ethpbalpha.Attestation{ + { + AggregationBits: bitfield.Bitlist{0x00}, + Data: ðpbalpha.AttestationData{ + Slot: 123, + CommitteeIndex: 123, + BeaconBlockRoot: bytesutil.PadTo([]byte("root1"), 32), + Source: ðpbalpha.Checkpoint{ + Epoch: 123, + Root: bytesutil.PadTo([]byte("root1"), 32), + }, + Target: ðpbalpha.Checkpoint{ + Epoch: 123, + Root: bytesutil.PadTo([]byte("root1"), 32), + }, + }, + Signature: bytesutil.PadTo([]byte("sig1"), 96), + }, + { + AggregationBits: bitfield.Bitlist{0x01}, + Data: ðpbalpha.AttestationData{ + Slot: 456, + CommitteeIndex: 456, + BeaconBlockRoot: bytesutil.PadTo([]byte("root2"), 32), + Source: ðpbalpha.Checkpoint{ + Epoch: 456, + Root: bytesutil.PadTo([]byte("root2"), 32), + }, + Target: ðpbalpha.Checkpoint{ + Epoch: 456, + Root: bytesutil.PadTo([]byte("root2"), 32), + }, + }, + Signature: bytesutil.PadTo([]byte("sig2"), 96), + }, + } + sb, err := blocks.NewSignedBeaconBlock(b) + require.NoError(t, err) + mockBlockFetcher := &testutil.MockBlocker{BlockToReturn: sb} + mockChainService := &mock.ChainService{ + FinalizedRoots: map[[32]byte]bool{}, + } + bs := &Server{ + OptimisticModeFetcher: mockChainService, + FinalizationFetcher: mockChainService, + Blocker: mockBlockFetcher, + } + + resp, err := bs.ListBlockAttestations(ctx, ðpbv1.BlockRequest{}) + require.NoError(t, err) + + v1Block, err := migration.V1Alpha1ToV1SignedBlock(b) + require.NoError(t, err) + assert.DeepEqual(t, v1Block.Block.Body.Attestations, resp.Data) + }) + t.Run("Altair", func(t *testing.T) { + b := util.NewBeaconBlockAltair() + b.Block.Body.Attestations = []*ethpbalpha.Attestation{ + { + AggregationBits: bitfield.Bitlist{0x00}, + Data: ðpbalpha.AttestationData{ + Slot: 123, + CommitteeIndex: 123, + BeaconBlockRoot: bytesutil.PadTo([]byte("root1"), 32), + Source: ðpbalpha.Checkpoint{ + Epoch: 123, + Root: bytesutil.PadTo([]byte("root1"), 32), + }, + Target: ðpbalpha.Checkpoint{ + Epoch: 123, + Root: bytesutil.PadTo([]byte("root1"), 32), + }, + }, + Signature: bytesutil.PadTo([]byte("sig1"), 96), + }, + { + AggregationBits: bitfield.Bitlist{0x01}, + Data: ðpbalpha.AttestationData{ + Slot: 456, + CommitteeIndex: 456, + BeaconBlockRoot: bytesutil.PadTo([]byte("root2"), 32), + Source: ðpbalpha.Checkpoint{ + Epoch: 456, + Root: bytesutil.PadTo([]byte("root2"), 32), + }, + Target: ðpbalpha.Checkpoint{ + Epoch: 456, + Root: bytesutil.PadTo([]byte("root2"), 32), + }, + }, + Signature: bytesutil.PadTo([]byte("sig2"), 96), + }, + } + sb, err := blocks.NewSignedBeaconBlock(b) + require.NoError(t, err) + mockBlockFetcher := &testutil.MockBlocker{BlockToReturn: sb} + mockChainService := &mock.ChainService{ + FinalizedRoots: map[[32]byte]bool{}, + } + bs := &Server{ + OptimisticModeFetcher: mockChainService, + FinalizationFetcher: mockChainService, + Blocker: mockBlockFetcher, + } + + resp, err := bs.ListBlockAttestations(ctx, ðpbv1.BlockRequest{}) + require.NoError(t, err) + + v1Block, err := migration.V1Alpha1BeaconBlockAltairToV2(b.Block) + require.NoError(t, err) + assert.DeepEqual(t, v1Block.Body.Attestations, resp.Data) + }) + t.Run("Bellatrix", func(t *testing.T) { + b := util.NewBeaconBlockBellatrix() + b.Block.Body.Attestations = []*ethpbalpha.Attestation{ + { + AggregationBits: bitfield.Bitlist{0x00}, + Data: ðpbalpha.AttestationData{ + Slot: 123, + CommitteeIndex: 123, + BeaconBlockRoot: bytesutil.PadTo([]byte("root1"), 32), + Source: ðpbalpha.Checkpoint{ + Epoch: 123, + Root: bytesutil.PadTo([]byte("root1"), 32), + }, + Target: ðpbalpha.Checkpoint{ + Epoch: 123, + Root: bytesutil.PadTo([]byte("root1"), 32), + }, + }, + Signature: bytesutil.PadTo([]byte("sig1"), 96), + }, + { + AggregationBits: bitfield.Bitlist{0x01}, + Data: ðpbalpha.AttestationData{ + Slot: 456, + CommitteeIndex: 456, + BeaconBlockRoot: bytesutil.PadTo([]byte("root2"), 32), + Source: ðpbalpha.Checkpoint{ + Epoch: 456, + Root: bytesutil.PadTo([]byte("root2"), 32), + }, + Target: ðpbalpha.Checkpoint{ + Epoch: 456, + Root: bytesutil.PadTo([]byte("root2"), 32), + }, + }, + Signature: bytesutil.PadTo([]byte("sig2"), 96), + }, + } + sb, err := blocks.NewSignedBeaconBlock(b) + require.NoError(t, err) + mockBlockFetcher := &testutil.MockBlocker{BlockToReturn: sb} + mockChainService := &mock.ChainService{ + FinalizedRoots: map[[32]byte]bool{}, + } + bs := &Server{ + OptimisticModeFetcher: mockChainService, + FinalizationFetcher: mockChainService, + Blocker: mockBlockFetcher, + } + + resp, err := bs.ListBlockAttestations(ctx, ðpbv1.BlockRequest{}) + require.NoError(t, err) + + v1Block, err := migration.V1Alpha1BeaconBlockBellatrixToV2(b.Block) + require.NoError(t, err) + assert.DeepEqual(t, v1Block.Body.Attestations, resp.Data) + }) + t.Run("Capella", func(t *testing.T) { + b := util.NewBeaconBlockCapella() + b.Block.Body.Attestations = []*ethpbalpha.Attestation{ + { + AggregationBits: bitfield.Bitlist{0x00}, + Data: ðpbalpha.AttestationData{ + Slot: 123, + CommitteeIndex: 123, + BeaconBlockRoot: bytesutil.PadTo([]byte("root1"), 32), + Source: ðpbalpha.Checkpoint{ + Epoch: 123, + Root: bytesutil.PadTo([]byte("root1"), 32), + }, + Target: ðpbalpha.Checkpoint{ + Epoch: 123, + Root: bytesutil.PadTo([]byte("root1"), 32), + }, + }, + Signature: bytesutil.PadTo([]byte("sig1"), 96), + }, + { + AggregationBits: bitfield.Bitlist{0x01}, + Data: ðpbalpha.AttestationData{ + Slot: 456, + CommitteeIndex: 456, + BeaconBlockRoot: bytesutil.PadTo([]byte("root2"), 32), + Source: ðpbalpha.Checkpoint{ + Epoch: 456, + Root: bytesutil.PadTo([]byte("root2"), 32), + }, + Target: ðpbalpha.Checkpoint{ + Epoch: 456, + Root: bytesutil.PadTo([]byte("root2"), 32), + }, + }, + Signature: bytesutil.PadTo([]byte("sig2"), 96), + }, + } + sb, err := blocks.NewSignedBeaconBlock(b) + require.NoError(t, err) + mockBlockFetcher := &testutil.MockBlocker{BlockToReturn: sb} + mockChainService := &mock.ChainService{ + FinalizedRoots: map[[32]byte]bool{}, + } + bs := &Server{ + OptimisticModeFetcher: mockChainService, + FinalizationFetcher: mockChainService, + Blocker: mockBlockFetcher, + } + + resp, err := bs.ListBlockAttestations(ctx, ðpbv1.BlockRequest{}) + require.NoError(t, err) + + v1Block, err := migration.V1Alpha1BeaconBlockCapellaToV2(b.Block) + require.NoError(t, err) + assert.DeepEqual(t, v1Block.Body.Attestations, resp.Data) + }) + t.Run("execution optimistic", func(t *testing.T) { + b := util.NewBeaconBlockBellatrix() + sb, err := blocks.NewSignedBeaconBlock(b) + require.NoError(t, err) + r, err := sb.Block().HashTreeRoot() + require.NoError(t, err) + mockBlockFetcher := &testutil.MockBlocker{BlockToReturn: sb} + mockChainService := &mock.ChainService{ + OptimisticRoots: map[[32]byte]bool{r: true}, + FinalizedRoots: map[[32]byte]bool{}, + } + bs := &Server{ + OptimisticModeFetcher: mockChainService, + FinalizationFetcher: mockChainService, + Blocker: mockBlockFetcher, + } + + resp, err := bs.ListBlockAttestations(ctx, ðpbv1.BlockRequest{}) + require.NoError(t, err) + assert.Equal(t, true, resp.ExecutionOptimistic) + }) + t.Run("finalized", func(t *testing.T) { + b := util.NewBeaconBlock() + sb, err := blocks.NewSignedBeaconBlock(b) + require.NoError(t, err) + r, err := sb.Block().HashTreeRoot() + require.NoError(t, err) + mockBlockFetcher := &testutil.MockBlocker{BlockToReturn: sb} + + t.Run("true", func(t *testing.T) { + mockChainService := &mock.ChainService{FinalizedRoots: map[[32]byte]bool{r: true}} + bs := &Server{ + OptimisticModeFetcher: mockChainService, + FinalizationFetcher: mockChainService, + Blocker: mockBlockFetcher, + } + + resp, err := bs.ListBlockAttestations(ctx, ðpbv1.BlockRequest{BlockId: r[:]}) + require.NoError(t, err) + assert.Equal(t, true, resp.Finalized) + }) + t.Run("false", func(t *testing.T) { + mockChainService := &mock.ChainService{FinalizedRoots: map[[32]byte]bool{r: false}} + bs := &Server{ + OptimisticModeFetcher: mockChainService, + FinalizationFetcher: mockChainService, + Blocker: mockBlockFetcher, + } + + resp, err := bs.ListBlockAttestations(ctx, ðpbv1.BlockRequest{BlockId: r[:]}) + require.NoError(t, err) assert.Equal(t, false, resp.Finalized) }) }) diff --git a/beacon-chain/rpc/eth/beacon/server.go b/beacon-chain/rpc/eth/beacon/server.go index 93636131ba50..def50b84b38d 100644 --- a/beacon-chain/rpc/eth/beacon/server.go +++ b/beacon-chain/rpc/eth/beacon/server.go @@ -14,8 +14,8 @@ import ( "github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/slashings" "github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/voluntaryexits" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p" + "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup" v1alpha1validator "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/prysm/v1alpha1/validator" - "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/statefetcher" "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen" "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync" ) @@ -34,7 +34,8 @@ type Server struct { SlashingsPool slashings.PoolManager VoluntaryExitsPool voluntaryexits.PoolManager StateGenService stategen.StateManager - StateFetcher statefetcher.Fetcher + Stater lookup.Stater + Blocker lookup.Blocker HeadFetcher blockchain.HeadFetcher OptimisticModeFetcher blockchain.OptimisticModeFetcher V1Alpha1ValidatorServer *v1alpha1validator.Server diff --git a/beacon-chain/rpc/eth/beacon/state.go b/beacon-chain/rpc/eth/beacon/state.go index dc19ca58a458..a057d274e6e1 100644 --- a/beacon-chain/rpc/eth/beacon/state.go +++ b/beacon-chain/rpc/eth/beacon/state.go @@ -6,7 +6,7 @@ import ( "strconv" "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/helpers" - "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/statefetcher" + "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup" "github.com/prysmaticlabs/prysm/v4/beacon-chain/state" "github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/consensus-types/primitives" @@ -58,20 +58,20 @@ func (bs *Server) GetStateRoot(ctx context.Context, req *ethpb.StateRequest) (*e ctx, span := trace.StartSpan(ctx, "beacon.GetStateRoot") defer span.End() - stateRoot, err := bs.StateFetcher.StateRoot(ctx, req.StateId) + stateRoot, err := bs.Stater.StateRoot(ctx, req.StateId) if err != nil { - if rootNotFoundErr, ok := err.(*statefetcher.StateRootNotFoundError); ok { + if rootNotFoundErr, ok := err.(*lookup.StateRootNotFoundError); ok { return nil, status.Errorf(codes.NotFound, "State root not found: %v", rootNotFoundErr) - } else if parseErr, ok := err.(*statefetcher.StateIdParseError); ok { + } else if parseErr, ok := err.(*lookup.StateIdParseError); ok { return nil, status.Errorf(codes.InvalidArgument, "Invalid state ID: %v", parseErr) } return nil, status.Errorf(codes.Internal, "Could not get state root: %v", err) } - st, err := bs.StateFetcher.State(ctx, req.StateId) + st, err := bs.Stater.State(ctx, req.StateId) if err != nil { return nil, status.Errorf(codes.Internal, "Could not get state: %v", err) } - isOptimistic, err := helpers.IsOptimistic(ctx, req.StateId, bs.OptimisticModeFetcher, bs.StateFetcher, bs.ChainInfoFetcher, bs.BeaconDB) + isOptimistic, err := helpers.IsOptimistic(ctx, req.StateId, bs.OptimisticModeFetcher, bs.Stater, bs.ChainInfoFetcher, bs.BeaconDB) if err != nil { return nil, status.Errorf(codes.Internal, "Could not check if slot's block is optimistic: %v", err) } @@ -95,12 +95,12 @@ func (bs *Server) GetStateFork(ctx context.Context, req *ethpb.StateRequest) (*e ctx, span := trace.StartSpan(ctx, "beacon.GetStateFork") defer span.End() - st, err := bs.StateFetcher.State(ctx, req.StateId) + st, err := bs.Stater.State(ctx, req.StateId) if err != nil { return nil, helpers.PrepareStateFetchGRPCError(err) } fork := st.Fork() - isOptimistic, err := helpers.IsOptimistic(ctx, req.StateId, bs.OptimisticModeFetcher, bs.StateFetcher, bs.ChainInfoFetcher, bs.BeaconDB) + isOptimistic, err := helpers.IsOptimistic(ctx, req.StateId, bs.OptimisticModeFetcher, bs.Stater, bs.ChainInfoFetcher, bs.BeaconDB) if err != nil { return nil, status.Errorf(codes.Internal, "Could not check if slot's block is optimistic: %v", err) } @@ -127,11 +127,11 @@ func (bs *Server) GetFinalityCheckpoints(ctx context.Context, req *ethpb.StateRe ctx, span := trace.StartSpan(ctx, "beacon.GetFinalityCheckpoints") defer span.End() - st, err := bs.StateFetcher.State(ctx, req.StateId) + st, err := bs.Stater.State(ctx, req.StateId) if err != nil { return nil, helpers.PrepareStateFetchGRPCError(err) } - isOptimistic, err := helpers.IsOptimistic(ctx, req.StateId, bs.OptimisticModeFetcher, bs.StateFetcher, bs.ChainInfoFetcher, bs.BeaconDB) + isOptimistic, err := helpers.IsOptimistic(ctx, req.StateId, bs.OptimisticModeFetcher, bs.Stater, bs.ChainInfoFetcher, bs.BeaconDB) if err != nil { return nil, status.Errorf(codes.Internal, "Could not check if slot's block is optimistic: %v", err) } @@ -160,7 +160,7 @@ func (bs *Server) GetRandao(ctx context.Context, req *eth2.RandaoRequest) (*eth2 ctx, span := trace.StartSpan(ctx, "beacon.GetRandao") defer span.End() - st, err := bs.StateFetcher.State(ctx, req.StateId) + st, err := bs.Stater.State(ctx, req.StateId) if err != nil { return nil, helpers.PrepareStateFetchGRPCError(err) } @@ -186,7 +186,7 @@ func (bs *Server) GetRandao(ctx context.Context, req *eth2.RandaoRequest) (*eth2 return nil, status.Errorf(codes.Internal, "Could not get randao mix at index %d", idx) } - isOptimistic, err := helpers.IsOptimistic(ctx, req.StateId, bs.OptimisticModeFetcher, bs.StateFetcher, bs.ChainInfoFetcher, bs.BeaconDB) + isOptimistic, err := helpers.IsOptimistic(ctx, req.StateId, bs.OptimisticModeFetcher, bs.Stater, bs.ChainInfoFetcher, bs.BeaconDB) if err != nil { return nil, status.Errorf(codes.Internal, "Could not check if slot's block is optimistic: %v", err) } @@ -215,14 +215,14 @@ func (bs *Server) stateFromRequest(ctx context.Context, req *stateRequest) (stat err, ) } - st, err := bs.StateFetcher.State(ctx, []byte(strconv.FormatUint(uint64(slot), 10))) + st, err := bs.Stater.State(ctx, []byte(strconv.FormatUint(uint64(slot), 10))) if err != nil { return nil, helpers.PrepareStateFetchGRPCError(err) } return st, nil } var err error - st, err := bs.StateFetcher.State(ctx, req.stateId) + st, err := bs.Stater.State(ctx, req.stateId) if err != nil { return nil, helpers.PrepareStateFetchGRPCError(err) } diff --git a/beacon-chain/rpc/eth/beacon/state_test.go b/beacon-chain/rpc/eth/beacon/state_test.go index 162c7e8017ab..97960ca8f193 100644 --- a/beacon-chain/rpc/eth/beacon/state_test.go +++ b/beacon-chain/rpc/eth/beacon/state_test.go @@ -83,7 +83,7 @@ func TestGetStateRoot(t *testing.T) { chainService := &chainMock.ChainService{} server := &Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconStateRoot: stateRoot[:], BeaconState: fakeState, }, @@ -111,7 +111,7 @@ func TestGetStateRoot(t *testing.T) { chainService := &chainMock.ChainService{Optimistic: true} server := &Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconStateRoot: stateRoot[:], BeaconState: fakeState, }, @@ -145,7 +145,7 @@ func TestGetStateRoot(t *testing.T) { }, } server := &Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconStateRoot: stateRoot[:], BeaconState: fakeState, }, @@ -179,7 +179,7 @@ func TestGetStateFork(t *testing.T) { chainService := &chainMock.ChainService{} server := &Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: fakeState, }, HeadFetcher: chainService, @@ -209,7 +209,7 @@ func TestGetStateFork(t *testing.T) { chainService := &chainMock.ChainService{Optimistic: true} server := &Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: fakeState, }, HeadFetcher: chainService, @@ -242,7 +242,7 @@ func TestGetStateFork(t *testing.T) { }, } server := &Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: fakeState, }, HeadFetcher: chainService, @@ -282,7 +282,7 @@ func TestGetFinalityCheckpoints(t *testing.T) { chainService := &chainMock.ChainService{} server := &Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: fakeState, }, HeadFetcher: chainService, @@ -314,7 +314,7 @@ func TestGetFinalityCheckpoints(t *testing.T) { chainService := &chainMock.ChainService{Optimistic: true} server := &Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: fakeState, }, HeadFetcher: chainService, @@ -347,7 +347,7 @@ func TestGetFinalityCheckpoints(t *testing.T) { }, } server := &Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: fakeState, }, HeadFetcher: chainService, @@ -388,7 +388,7 @@ func TestGetRandao(t *testing.T) { db := dbTest.SetupDB(t) chainService := &chainMock.ChainService{} server := &Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: st, }, HeadFetcher: chainService, @@ -413,7 +413,7 @@ func TestGetRandao(t *testing.T) { assert.DeepEqual(t, mixOld, resp.Data.Randao) }) t.Run("head state below `EpochsPerHistoricalVector`", func(t *testing.T) { - server.StateFetcher = &testutil.MockFetcher{ + server.Stater = &testutil.MockStater{ BeaconState: headSt, } resp, err := server.GetRandao(ctx, ð2.RandaoRequest{StateId: []byte("head")}) @@ -441,7 +441,7 @@ func TestGetRandao(t *testing.T) { chainService := &chainMock.ChainService{Optimistic: true} server := &Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: st, }, HeadFetcher: chainService, @@ -473,7 +473,7 @@ func TestGetRandao(t *testing.T) { }, } server := &Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: st, }, HeadFetcher: chainService, diff --git a/beacon-chain/rpc/eth/beacon/sync_committee.go b/beacon-chain/rpc/eth/beacon/sync_committee.go index 266e2085a9d1..9a414d082d9a 100644 --- a/beacon-chain/rpc/eth/beacon/sync_committee.go +++ b/beacon-chain/rpc/eth/beacon/sync_committee.go @@ -91,7 +91,7 @@ func (bs *Server) ListSyncCommittees(ctx context.Context, req *ethpbv2.StateSync return nil, status.Errorf(codes.Internal, "Could not extract sync subcommittees: %v", err) } - isOptimistic, err := helpers.IsOptimistic(ctx, req.StateId, bs.OptimisticModeFetcher, bs.StateFetcher, bs.ChainInfoFetcher, bs.BeaconDB) + isOptimistic, err := helpers.IsOptimistic(ctx, req.StateId, bs.OptimisticModeFetcher, bs.Stater, bs.ChainInfoFetcher, bs.BeaconDB) if err != nil { return nil, status.Errorf(codes.Internal, "Could not check if slot's block is optimistic: %v", err) } diff --git a/beacon-chain/rpc/eth/beacon/sync_committee_test.go b/beacon-chain/rpc/eth/beacon/sync_committee_test.go index 1416b7415542..5d08c19356b6 100644 --- a/beacon-chain/rpc/eth/beacon/sync_committee_test.go +++ b/beacon-chain/rpc/eth/beacon/sync_committee_test.go @@ -167,7 +167,7 @@ func TestListSyncCommittees(t *testing.T) { GenesisTimeFetcher: &testutil.MockGenesisTimeFetcher{ Genesis: time.Now(), }, - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: st, }, HeadFetcher: chainService, @@ -213,7 +213,7 @@ func TestListSyncCommittees(t *testing.T) { GenesisTimeFetcher: &testutil.MockGenesisTimeFetcher{ Genesis: time.Now(), }, - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: st, }, HeadFetcher: chainService, @@ -249,7 +249,7 @@ func TestListSyncCommittees(t *testing.T) { GenesisTimeFetcher: &testutil.MockGenesisTimeFetcher{ Genesis: time.Now(), }, - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: st, }, HeadFetcher: chainService, @@ -309,7 +309,7 @@ func TestListSyncCommitteesFuture(t *testing.T) { GenesisTimeFetcher: &testutil.MockGenesisTimeFetcher{ Genesis: time.Now(), }, - StateFetcher: &futureSyncMockFetcher{ + Stater: &futureSyncMockFetcher{ BeaconState: st, }, HeadFetcher: chainService, diff --git a/beacon-chain/rpc/eth/beacon/validator.go b/beacon-chain/rpc/eth/beacon/validator.go index bb808aebf10c..c79d7e2bc474 100644 --- a/beacon-chain/rpc/eth/beacon/validator.go +++ b/beacon-chain/rpc/eth/beacon/validator.go @@ -42,7 +42,7 @@ func (bs *Server) GetValidator(ctx context.Context, req *ethpb.StateValidatorReq ctx, span := trace.StartSpan(ctx, "beacon.GetValidator") defer span.End() - st, err := bs.StateFetcher.State(ctx, req.StateId) + st, err := bs.Stater.State(ctx, req.StateId) if err != nil { return nil, helpers.PrepareStateFetchGRPCError(err) } @@ -57,7 +57,7 @@ func (bs *Server) GetValidator(ctx context.Context, req *ethpb.StateValidatorReq return nil, status.Error(codes.NotFound, "Could not find validator") } - isOptimistic, err := helpers.IsOptimistic(ctx, req.StateId, bs.OptimisticModeFetcher, bs.StateFetcher, bs.ChainInfoFetcher, bs.BeaconDB) + isOptimistic, err := helpers.IsOptimistic(ctx, req.StateId, bs.OptimisticModeFetcher, bs.Stater, bs.ChainInfoFetcher, bs.BeaconDB) if err != nil { return nil, status.Errorf(codes.Internal, "Could not check if slot's block is optimistic: %v", err) } @@ -76,7 +76,7 @@ func (bs *Server) ListValidators(ctx context.Context, req *ethpb.StateValidators ctx, span := trace.StartSpan(ctx, "beacon.ListValidators") defer span.End() - st, err := bs.StateFetcher.State(ctx, req.StateId) + st, err := bs.Stater.State(ctx, req.StateId) if err != nil { return nil, helpers.PrepareStateFetchGRPCError(err) } @@ -86,7 +86,7 @@ func (bs *Server) ListValidators(ctx context.Context, req *ethpb.StateValidators return nil, handleValContainerErr(err) } - isOptimistic, err := helpers.IsOptimistic(ctx, req.StateId, bs.OptimisticModeFetcher, bs.StateFetcher, bs.ChainInfoFetcher, bs.BeaconDB) + isOptimistic, err := helpers.IsOptimistic(ctx, req.StateId, bs.OptimisticModeFetcher, bs.Stater, bs.ChainInfoFetcher, bs.BeaconDB) if err != nil { return nil, status.Errorf(codes.Internal, "Could not check if slot's block is optimistic: %v", err) } @@ -138,7 +138,7 @@ func (bs *Server) ListValidatorBalances(ctx context.Context, req *ethpb.Validato ctx, span := trace.StartSpan(ctx, "beacon.ListValidatorBalances") defer span.End() - st, err := bs.StateFetcher.State(ctx, req.StateId) + st, err := bs.Stater.State(ctx, req.StateId) if err != nil { return nil, helpers.PrepareStateFetchGRPCError(err) } @@ -155,7 +155,7 @@ func (bs *Server) ListValidatorBalances(ctx context.Context, req *ethpb.Validato } } - isOptimistic, err := helpers.IsOptimistic(ctx, req.StateId, bs.OptimisticModeFetcher, bs.StateFetcher, bs.ChainInfoFetcher, bs.BeaconDB) + isOptimistic, err := helpers.IsOptimistic(ctx, req.StateId, bs.OptimisticModeFetcher, bs.Stater, bs.ChainInfoFetcher, bs.BeaconDB) if err != nil { return nil, status.Errorf(codes.Internal, "Could not check if slot's block is optimistic: %v", err) } @@ -175,7 +175,7 @@ func (bs *Server) ListCommittees(ctx context.Context, req *ethpb.StateCommittees ctx, span := trace.StartSpan(ctx, "beacon.ListCommittees") defer span.End() - st, err := bs.StateFetcher.State(ctx, req.StateId) + st, err := bs.Stater.State(ctx, req.StateId) if err != nil { return nil, helpers.PrepareStateFetchGRPCError(err) } @@ -220,7 +220,7 @@ func (bs *Server) ListCommittees(ctx context.Context, req *ethpb.StateCommittees } } - isOptimistic, err := helpers.IsOptimistic(ctx, req.StateId, bs.OptimisticModeFetcher, bs.StateFetcher, bs.ChainInfoFetcher, bs.BeaconDB) + isOptimistic, err := helpers.IsOptimistic(ctx, req.StateId, bs.OptimisticModeFetcher, bs.Stater, bs.ChainInfoFetcher, bs.BeaconDB) if err != nil { return nil, status.Errorf(codes.Internal, "Could not check if slot's block is optimistic: %v", err) } diff --git a/beacon-chain/rpc/eth/beacon/validator_test.go b/beacon-chain/rpc/eth/beacon/validator_test.go index 7081ab0eddc3..bca1f7f61360 100644 --- a/beacon-chain/rpc/eth/beacon/validator_test.go +++ b/beacon-chain/rpc/eth/beacon/validator_test.go @@ -9,7 +9,7 @@ import ( chainMock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing" dbTest "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing" rpchelpers "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/helpers" - "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/statefetcher" + "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup" "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/testutil" "github.com/prysmaticlabs/prysm/v4/beacon-chain/state" state_native "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native" @@ -34,7 +34,7 @@ func TestGetValidator(t *testing.T) { t.Run("Head Get Validator by index", func(t *testing.T) { chainService := &chainMock.ChainService{} s := Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: st, }, HeadFetcher: chainService, @@ -54,7 +54,7 @@ func TestGetValidator(t *testing.T) { t.Run("Head Get Validator by pubkey", func(t *testing.T) { chainService := &chainMock.ChainService{} s := Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: st, }, HeadFetcher: chainService, @@ -75,7 +75,7 @@ func TestGetValidator(t *testing.T) { t.Run("Validator ID required", func(t *testing.T) { s := Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: st, }, HeadFetcher: &chainMock.ChainService{}, @@ -98,7 +98,7 @@ func TestGetValidator(t *testing.T) { chainService := &chainMock.ChainService{Optimistic: true} s := Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: st, }, HeadFetcher: chainService, @@ -131,7 +131,7 @@ func TestGetValidator(t *testing.T) { }, } s := Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: st, }, HeadFetcher: chainService, @@ -157,7 +157,7 @@ func TestListValidators(t *testing.T) { t.Run("Head List All Validators", func(t *testing.T) { chainService := &chainMock.ChainService{} s := Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: st, }, HeadFetcher: chainService, @@ -179,7 +179,7 @@ func TestListValidators(t *testing.T) { t.Run("Head List Validators by index", func(t *testing.T) { chainService := &chainMock.ChainService{} s := Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: st, }, HeadFetcher: chainService, @@ -204,7 +204,7 @@ func TestListValidators(t *testing.T) { t.Run("Head List Validators by pubkey", func(t *testing.T) { chainService := &chainMock.ChainService{} s := Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: st, }, HeadFetcher: chainService, @@ -233,7 +233,7 @@ func TestListValidators(t *testing.T) { t.Run("Head List Validators by both index and pubkey", func(t *testing.T) { chainService := &chainMock.ChainService{} s := Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: st, }, HeadFetcher: chainService, @@ -264,7 +264,7 @@ func TestListValidators(t *testing.T) { t.Run("Unknown public key is ignored", func(t *testing.T) { chainService := &chainMock.ChainService{} s := Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: st, }, HeadFetcher: chainService, @@ -287,7 +287,7 @@ func TestListValidators(t *testing.T) { t.Run("Unknown index is ignored", func(t *testing.T) { chainService := &chainMock.ChainService{} s := Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: st, }, HeadFetcher: chainService, @@ -317,7 +317,7 @@ func TestListValidators(t *testing.T) { chainService := &chainMock.ChainService{Optimistic: true} s := Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: st, }, HeadFetcher: chainService, @@ -349,7 +349,7 @@ func TestListValidators(t *testing.T) { }, } s := Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: st, }, HeadFetcher: chainService, @@ -440,7 +440,7 @@ func TestListValidators_Status(t *testing.T) { t.Run("Head List All ACTIVE Validators", func(t *testing.T) { chainService := &chainMock.ChainService{} s := Server{ - StateFetcher: &statefetcher.StateProvider{ + Stater: &lookup.BeaconDbStater{ ChainInfoFetcher: &chainMock.ChainService{State: st}, }, HeadFetcher: chainService, @@ -478,7 +478,7 @@ func TestListValidators_Status(t *testing.T) { t.Run("Head List All ACTIVE_ONGOING Validators", func(t *testing.T) { chainService := &chainMock.ChainService{} s := Server{ - StateFetcher: &statefetcher.StateProvider{ + Stater: &lookup.BeaconDbStater{ ChainInfoFetcher: &chainMock.ChainService{State: st}, }, HeadFetcher: chainService, @@ -515,7 +515,7 @@ func TestListValidators_Status(t *testing.T) { t.Run("Head List All EXITED Validators", func(t *testing.T) { chainService := &chainMock.ChainService{} s := Server{ - StateFetcher: &statefetcher.StateProvider{ + Stater: &lookup.BeaconDbStater{ ChainInfoFetcher: &chainMock.ChainService{State: st}, }, HeadFetcher: chainService, @@ -551,7 +551,7 @@ func TestListValidators_Status(t *testing.T) { t.Run("Head List All PENDING_INITIALIZED and EXITED_UNSLASHED Validators", func(t *testing.T) { chainService := &chainMock.ChainService{} s := Server{ - StateFetcher: &statefetcher.StateProvider{ + Stater: &lookup.BeaconDbStater{ ChainInfoFetcher: &chainMock.ChainService{State: st}, }, HeadFetcher: chainService, @@ -587,7 +587,7 @@ func TestListValidators_Status(t *testing.T) { t.Run("Head List All PENDING and EXITED Validators", func(t *testing.T) { chainService := &chainMock.ChainService{} s := Server{ - StateFetcher: &statefetcher.StateProvider{ + Stater: &lookup.BeaconDbStater{ ChainInfoFetcher: &chainMock.ChainService{State: st}, }, HeadFetcher: chainService, @@ -638,7 +638,7 @@ func TestListValidatorBalances(t *testing.T) { t.Run("Head List Validators Balance by index", func(t *testing.T) { chainService := &chainMock.ChainService{} s := Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: st, }, HeadFetcher: chainService, @@ -663,7 +663,7 @@ func TestListValidatorBalances(t *testing.T) { t.Run("Head List Validators Balance by pubkey", func(t *testing.T) { chainService := &chainMock.ChainService{} s := Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: st, }, HeadFetcher: chainService, @@ -691,7 +691,7 @@ func TestListValidatorBalances(t *testing.T) { t.Run("Head List Validators Balance by both index and pubkey", func(t *testing.T) { chainService := &chainMock.ChainService{} s := Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: st, }, HeadFetcher: chainService, @@ -726,7 +726,7 @@ func TestListValidatorBalances(t *testing.T) { chainService := &chainMock.ChainService{Optimistic: true} s := Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: st, }, HeadFetcher: chainService, @@ -761,7 +761,7 @@ func TestListValidatorBalances(t *testing.T) { }, } s := Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: st, }, HeadFetcher: chainService, @@ -791,7 +791,7 @@ func TestListCommittees(t *testing.T) { t.Run("Head All Committees", func(t *testing.T) { chainService := &chainMock.ChainService{} s := Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: st, }, HeadFetcher: chainService, @@ -814,7 +814,7 @@ func TestListCommittees(t *testing.T) { t.Run("Head All Committees of Epoch 10", func(t *testing.T) { chainService := &chainMock.ChainService{} s := Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: st, }, HeadFetcher: chainService, @@ -836,7 +836,7 @@ func TestListCommittees(t *testing.T) { t.Run("Head All Committees of Slot 4", func(t *testing.T) { chainService := &chainMock.ChainService{} s := Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: st, }, HeadFetcher: chainService, @@ -864,7 +864,7 @@ func TestListCommittees(t *testing.T) { t.Run("Head All Committees of Index 1", func(t *testing.T) { chainService := &chainMock.ChainService{} s := Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: st, }, HeadFetcher: chainService, @@ -892,7 +892,7 @@ func TestListCommittees(t *testing.T) { t.Run("Head All Committees of Slot 2, Index 1", func(t *testing.T) { chainService := &chainMock.ChainService{} s := Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: st, }, HeadFetcher: chainService, @@ -928,7 +928,7 @@ func TestListCommittees(t *testing.T) { chainService := &chainMock.ChainService{Optimistic: true} s := Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: st, }, HeadFetcher: chainService, @@ -961,7 +961,7 @@ func TestListCommittees(t *testing.T) { }, } s := Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: st, }, HeadFetcher: chainService, diff --git a/beacon-chain/rpc/eth/debug/BUILD.bazel b/beacon-chain/rpc/eth/debug/BUILD.bazel index 7de47ffe5204..6400f3e9c86e 100644 --- a/beacon-chain/rpc/eth/debug/BUILD.bazel +++ b/beacon-chain/rpc/eth/debug/BUILD.bazel @@ -12,7 +12,7 @@ go_library( "//beacon-chain/blockchain:go_default_library", "//beacon-chain/db:go_default_library", "//beacon-chain/rpc/eth/helpers:go_default_library", - "//beacon-chain/rpc/statefetcher:go_default_library", + "//beacon-chain/rpc/lookup:go_default_library", "//proto/eth/v1:go_default_library", "//proto/eth/v2:go_default_library", "//proto/migration:go_default_library", diff --git a/beacon-chain/rpc/eth/debug/debug.go b/beacon-chain/rpc/eth/debug/debug.go index a757f9c01d09..493108f16af0 100644 --- a/beacon-chain/rpc/eth/debug/debug.go +++ b/beacon-chain/rpc/eth/debug/debug.go @@ -19,7 +19,7 @@ func (ds *Server) GetBeaconStateSSZ(ctx context.Context, req *ethpbv1.StateReque ctx, span := trace.StartSpan(ctx, "debug.GetBeaconStateSSZ") defer span.End() - state, err := ds.StateFetcher.State(ctx, req.StateId) + state, err := ds.Stater.State(ctx, req.StateId) if err != nil { return nil, helpers.PrepareStateFetchGRPCError(err) } @@ -37,11 +37,11 @@ func (ds *Server) GetBeaconStateV2(ctx context.Context, req *ethpbv2.BeaconState ctx, span := trace.StartSpan(ctx, "debug.GetBeaconStateV2") defer span.End() - beaconSt, err := ds.StateFetcher.State(ctx, req.StateId) + beaconSt, err := ds.Stater.State(ctx, req.StateId) if err != nil { return nil, helpers.PrepareStateFetchGRPCError(err) } - isOptimistic, err := helpers.IsOptimistic(ctx, req.StateId, ds.OptimisticModeFetcher, ds.StateFetcher, ds.ChainInfoFetcher, ds.BeaconDB) + isOptimistic, err := helpers.IsOptimistic(ctx, req.StateId, ds.OptimisticModeFetcher, ds.Stater, ds.ChainInfoFetcher, ds.BeaconDB) if err != nil { return nil, status.Errorf(codes.Internal, "Could not check if slot's block is optimistic: %v", err) } @@ -114,7 +114,7 @@ func (ds *Server) GetBeaconStateSSZV2(ctx context.Context, req *ethpbv2.BeaconSt ctx, span := trace.StartSpan(ctx, "debug.GetBeaconStateSSZV2") defer span.End() - st, err := ds.StateFetcher.State(ctx, req.StateId) + st, err := ds.Stater.State(ctx, req.StateId) if err != nil { return nil, helpers.PrepareStateFetchGRPCError(err) } diff --git a/beacon-chain/rpc/eth/debug/debug_test.go b/beacon-chain/rpc/eth/debug/debug_test.go index 750f2185bcd5..7c772e89baef 100644 --- a/beacon-chain/rpc/eth/debug/debug_test.go +++ b/beacon-chain/rpc/eth/debug/debug_test.go @@ -28,7 +28,7 @@ func TestGetBeaconStateV2(t *testing.T) { fakeState, err := util.NewBeaconState() require.NoError(t, err) server := &Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: fakeState, }, HeadFetcher: &blockchainmock.ChainService{}, @@ -46,7 +46,7 @@ func TestGetBeaconStateV2(t *testing.T) { t.Run("Altair", func(t *testing.T) { fakeState, _ := util.DeterministicGenesisStateAltair(t, 1) server := &Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: fakeState, }, HeadFetcher: &blockchainmock.ChainService{}, @@ -64,7 +64,7 @@ func TestGetBeaconStateV2(t *testing.T) { t.Run("Bellatrix", func(t *testing.T) { fakeState, _ := util.DeterministicGenesisStateBellatrix(t, 1) server := &Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: fakeState, }, HeadFetcher: &blockchainmock.ChainService{}, @@ -82,7 +82,7 @@ func TestGetBeaconStateV2(t *testing.T) { t.Run("Capella", func(t *testing.T) { fakeState, _ := util.DeterministicGenesisStateCapella(t, 1) server := &Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: fakeState, }, HeadFetcher: &blockchainmock.ChainService{}, @@ -108,7 +108,7 @@ func TestGetBeaconStateV2(t *testing.T) { fakeState, _ := util.DeterministicGenesisStateBellatrix(t, 1) server := &Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: fakeState, }, HeadFetcher: &blockchainmock.ChainService{}, @@ -141,7 +141,7 @@ func TestGetBeaconStateV2(t *testing.T) { }, } server := &Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: fakeState, }, HeadFetcher: chainService, @@ -165,7 +165,7 @@ func TestGetBeaconStateSSZ(t *testing.T) { require.NoError(t, err) server := &Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: fakeState, }, } @@ -186,7 +186,7 @@ func TestGetBeaconStateSSZV2(t *testing.T) { require.NoError(t, err) server := &Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: fakeState, }, } @@ -205,7 +205,7 @@ func TestGetBeaconStateSSZV2(t *testing.T) { require.NoError(t, err) server := &Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: fakeState, }, } @@ -224,7 +224,7 @@ func TestGetBeaconStateSSZV2(t *testing.T) { require.NoError(t, err) server := &Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: fakeState, }, } @@ -243,7 +243,7 @@ func TestGetBeaconStateSSZV2(t *testing.T) { require.NoError(t, err) server := &Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ BeaconState: fakeState, }, } diff --git a/beacon-chain/rpc/eth/debug/server.go b/beacon-chain/rpc/eth/debug/server.go index 2696cdbd8ba4..2c5ccbd0c973 100644 --- a/beacon-chain/rpc/eth/debug/server.go +++ b/beacon-chain/rpc/eth/debug/server.go @@ -6,7 +6,7 @@ package debug import ( "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain" "github.com/prysmaticlabs/prysm/v4/beacon-chain/db" - "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/statefetcher" + "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup" ) // Server defines a server implementation of the gRPC Beacon Chain service, @@ -14,7 +14,7 @@ import ( type Server struct { BeaconDB db.ReadOnlyDatabase HeadFetcher blockchain.HeadFetcher - StateFetcher statefetcher.Fetcher + Stater lookup.Stater OptimisticModeFetcher blockchain.OptimisticModeFetcher ForkFetcher blockchain.ForkFetcher ForkchoiceFetcher blockchain.ForkchoiceFetcher diff --git a/beacon-chain/rpc/eth/helpers/BUILD.bazel b/beacon-chain/rpc/eth/helpers/BUILD.bazel index 2b40430813ac..b72a4950bcc9 100644 --- a/beacon-chain/rpc/eth/helpers/BUILD.bazel +++ b/beacon-chain/rpc/eth/helpers/BUILD.bazel @@ -13,7 +13,7 @@ go_library( "//api/grpc:go_default_library", "//beacon-chain/blockchain:go_default_library", "//beacon-chain/db:go_default_library", - "//beacon-chain/rpc/statefetcher:go_default_library", + "//beacon-chain/rpc/lookup:go_default_library", "//beacon-chain/state:go_default_library", "//beacon-chain/state/stategen:go_default_library", "//beacon-chain/sync:go_default_library", diff --git a/beacon-chain/rpc/eth/helpers/error_handling.go b/beacon-chain/rpc/eth/helpers/error_handling.go index 73ccd8e93ee9..8e2967a36bb8 100644 --- a/beacon-chain/rpc/eth/helpers/error_handling.go +++ b/beacon-chain/rpc/eth/helpers/error_handling.go @@ -3,7 +3,7 @@ package helpers import ( "errors" - "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/statefetcher" + "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup" "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -15,10 +15,10 @@ func PrepareStateFetchGRPCError(err error) error { if errors.Is(err, stategen.ErrNoDataForSlot) { return status.Errorf(codes.NotFound, "lacking historical data needed to fulfill request") } - if stateNotFoundErr, ok := err.(*statefetcher.StateNotFoundError); ok { + if stateNotFoundErr, ok := err.(*lookup.StateNotFoundError); ok { return status.Errorf(codes.NotFound, "State not found: %v", stateNotFoundErr) } - if parseErr, ok := err.(*statefetcher.StateIdParseError); ok { + if parseErr, ok := err.(*lookup.StateIdParseError); ok { return status.Errorf(codes.InvalidArgument, "Invalid state ID: %v", parseErr) } return status.Errorf(codes.Internal, "Invalid state ID: %v", err) diff --git a/beacon-chain/rpc/eth/helpers/sync.go b/beacon-chain/rpc/eth/helpers/sync.go index 4a07a238889d..87f835d1aa44 100644 --- a/beacon-chain/rpc/eth/helpers/sync.go +++ b/beacon-chain/rpc/eth/helpers/sync.go @@ -9,7 +9,7 @@ import ( "github.com/prysmaticlabs/prysm/v4/api/grpc" "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain" "github.com/prysmaticlabs/prysm/v4/beacon-chain/db" - "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/statefetcher" + "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup" "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync" "github.com/prysmaticlabs/prysm/v4/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v4/encoding/bytesutil" @@ -61,7 +61,7 @@ func IsOptimistic( ctx context.Context, stateId []byte, optimisticModeFetcher blockchain.OptimisticModeFetcher, - stateFetcher statefetcher.Fetcher, + stateFetcher lookup.Stater, chainInfo blockchain.ChainInfoFetcher, database db.ReadOnlyDatabase, ) (bool, error) { @@ -97,7 +97,7 @@ func IsOptimistic( slotNumber, parseErr := strconv.ParseUint(stateIdString, 10, 64) if parseErr != nil { // ID format does not match any valid options. - e := statefetcher.NewStateIdParseError(parseErr) + e := lookup.NewStateIdParseError(parseErr) return true, &e } fcp := chainInfo.FinalizedCheckpt() @@ -146,7 +146,7 @@ func isStateRootOptimistic( ctx context.Context, stateId []byte, optimisticModeFetcher blockchain.OptimisticModeFetcher, - stateFetcher statefetcher.Fetcher, + stateFetcher lookup.Stater, chainInfo blockchain.ChainInfoFetcher, database db.ReadOnlyDatabase, ) (bool, error) { diff --git a/beacon-chain/rpc/eth/helpers/sync_test.go b/beacon-chain/rpc/eth/helpers/sync_test.go index 2ad142ba3eaf..527880b5f33d 100644 --- a/beacon-chain/rpc/eth/helpers/sync_test.go +++ b/beacon-chain/rpc/eth/helpers/sync_test.go @@ -97,7 +97,7 @@ func TestIsOptimistic(t *testing.T) { st, err := util.NewBeaconState() require.NoError(t, err) cs := &chainmock.ChainService{Optimistic: true, FinalizedCheckPoint: ð.Checkpoint{}, OptimisticRoots: map[[32]byte]bool{[32]byte{}: true}} - mf := &testutil.MockFetcher{BeaconState: st} + mf := &testutil.MockStater{BeaconState: st} o, err := IsOptimistic(ctx, []byte("finalized"), cs, mf, cs, nil) require.NoError(t, err) assert.Equal(t, true, o) @@ -106,7 +106,7 @@ func TestIsOptimistic(t *testing.T) { st, err := util.NewBeaconState() require.NoError(t, err) cs := &chainmock.ChainService{Optimistic: true, FinalizedCheckPoint: ð.Checkpoint{}} - mf := &testutil.MockFetcher{BeaconState: st} + mf := &testutil.MockStater{BeaconState: st} o, err := IsOptimistic(ctx, []byte("finalized"), cs, mf, cs, nil) require.NoError(t, err) assert.Equal(t, false, o) @@ -117,7 +117,7 @@ func TestIsOptimistic(t *testing.T) { st, err := util.NewBeaconState() require.NoError(t, err) cs := &chainmock.ChainService{Optimistic: true, CurrentJustifiedCheckPoint: ð.Checkpoint{}, OptimisticRoots: map[[32]byte]bool{[32]byte{}: true}} - mf := &testutil.MockFetcher{BeaconState: st} + mf := &testutil.MockStater{BeaconState: st} o, err := IsOptimistic(ctx, []byte("justified"), cs, mf, cs, nil) require.NoError(t, err) assert.Equal(t, true, o) @@ -126,7 +126,7 @@ func TestIsOptimistic(t *testing.T) { st, err := util.NewBeaconState() require.NoError(t, err) cs := &chainmock.ChainService{Optimistic: true, CurrentJustifiedCheckPoint: ð.Checkpoint{}} - mf := &testutil.MockFetcher{BeaconState: st} + mf := &testutil.MockStater{BeaconState: st} o, err := IsOptimistic(ctx, []byte("justified"), cs, mf, cs, nil) require.NoError(t, err) assert.Equal(t, false, o) @@ -137,7 +137,7 @@ func TestIsOptimistic(t *testing.T) { st, err := util.NewBeaconState() require.NoError(t, err) cs := &chainmock.ChainService{Optimistic: true} - mf := &testutil.MockFetcher{BeaconState: st} + mf := &testutil.MockStater{BeaconState: st} o, err := IsOptimistic(ctx, bytesutil.PadTo([]byte("root"), 32), cs, mf, cs, nil) require.NoError(t, err) assert.Equal(t, true, o) @@ -146,7 +146,7 @@ func TestIsOptimistic(t *testing.T) { st, err := util.NewBeaconState() require.NoError(t, err) cs := &chainmock.ChainService{Optimistic: false} - mf := &testutil.MockFetcher{BeaconState: st} + mf := &testutil.MockStater{BeaconState: st} o, err := IsOptimistic(ctx, bytesutil.PadTo([]byte("root"), 32), cs, mf, cs, nil) require.NoError(t, err) assert.Equal(t, false, o) @@ -165,7 +165,7 @@ func TestIsOptimistic(t *testing.T) { bRoot, err := b.Block().HashTreeRoot() require.NoError(t, err) cs := &chainmock.ChainService{State: chainSt, OptimisticRoots: map[[32]byte]bool{bRoot: true}} - mf := &testutil.MockFetcher{BeaconState: fetcherSt} + mf := &testutil.MockStater{BeaconState: fetcherSt} o, err := IsOptimistic(ctx, bytesutil.PadTo([]byte("root"), 32), cs, mf, cs, db) require.NoError(t, err) assert.Equal(t, true, o) @@ -182,7 +182,7 @@ func TestIsOptimistic(t *testing.T) { require.NoError(t, err) require.NoError(t, chainSt.SetSlot(fieldparams.SlotsPerEpoch)) cs := &chainmock.ChainService{State: chainSt} - mf := &testutil.MockFetcher{BeaconState: fetcherSt} + mf := &testutil.MockStater{BeaconState: fetcherSt} o, err := IsOptimistic(ctx, bytesutil.PadTo([]byte("root"), 32), cs, mf, cs, db) require.NoError(t, err) assert.Equal(t, false, o) @@ -198,7 +198,7 @@ func TestIsOptimistic(t *testing.T) { require.NoError(t, err) require.NoError(t, chainSt.SetSlot(fieldparams.SlotsPerEpoch)) cs := &chainmock.ChainService{Optimistic: false, State: chainSt, CanonicalRoots: map[[32]byte]bool{}} - mf := &testutil.MockFetcher{BeaconState: fetcherSt} + mf := &testutil.MockStater{BeaconState: fetcherSt} o, err := IsOptimistic(ctx, bytesutil.PadTo([]byte("root"), 32), nil, mf, cs, db) require.NoError(t, err) assert.Equal(t, true, o) @@ -248,7 +248,7 @@ func TestIsOptimistic(t *testing.T) { require.NoError(t, err) require.NoError(t, chainSt.SetSlot(fieldparams.SlotsPerEpoch*2)) cs := &chainmock.ChainService{Optimistic: true, State: chainSt, FinalizedCheckPoint: ð.Checkpoint{Epoch: 0}} - mf := &testutil.MockFetcher{BeaconState: fetcherSt} + mf := &testutil.MockStater{BeaconState: fetcherSt} o, err := IsOptimistic(ctx, []byte(strconv.Itoa(fieldparams.SlotsPerEpoch*2)), cs, mf, cs, db) require.NoError(t, err) assert.Equal(t, true, o) @@ -268,7 +268,7 @@ func TestIsOptimistic(t *testing.T) { require.NoError(t, err) require.NoError(t, fcs.InsertNode(ctx, st, root)) cs := &chainmock.ChainService{Root: headRoot[:], Optimistic: true, ForkChoiceStore: fcs, OptimisticRoots: map[[32]byte]bool{r: true}, FinalizedCheckPoint: finalizedCheckpt} - mf := &testutil.MockFetcher{BeaconState: st} + mf := &testutil.MockStater{BeaconState: st} o, err := IsOptimistic(ctx, []byte(strconv.Itoa(fieldparams.SlotsPerEpoch*2)), cs, mf, cs, db) require.NoError(t, err) assert.Equal(t, true, o) @@ -288,7 +288,7 @@ func TestIsOptimistic(t *testing.T) { require.NoError(t, err) require.NoError(t, fcs.InsertNode(ctx, st, root)) cs := &chainmock.ChainService{Root: headRoot[:], Optimistic: true, ForkChoiceStore: fcs, OptimisticRoots: map[[32]byte]bool{r: false}, FinalizedCheckPoint: finalizedCheckpt} - mf := &testutil.MockFetcher{BeaconState: st} + mf := &testutil.MockStater{BeaconState: st} o, err := IsOptimistic(ctx, []byte(strconv.Itoa(fieldparams.SlotsPerEpoch*2)), cs, mf, cs, db) require.NoError(t, err) assert.Equal(t, false, o) diff --git a/beacon-chain/rpc/eth/rewards/BUILD.bazel b/beacon-chain/rpc/eth/rewards/BUILD.bazel new file mode 100644 index 000000000000..78d6df3712a8 --- /dev/null +++ b/beacon-chain/rpc/eth/rewards/BUILD.bazel @@ -0,0 +1,52 @@ +load("@prysm//tools/go:def.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = [ + "handlers.go", + "server.go", + "structs.go", + ], + importpath = "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/rewards", + visibility = ["//visibility:public"], + deps = [ + "//beacon-chain/blockchain:go_default_library", + "//beacon-chain/core/altair:go_default_library", + "//beacon-chain/core/blocks:go_default_library", + "//beacon-chain/core/validators:go_default_library", + "//beacon-chain/rpc/lookup:go_default_library", + "//beacon-chain/state/stategen:go_default_library", + "//consensus-types/blocks:go_default_library", + "//consensus-types/interfaces:go_default_library", + "//network:go_default_library", + "//runtime/version:go_default_library", + "@com_github_pkg_errors//:go_default_library", + ], +) + +go_test( + name = "go_default_test", + srcs = ["handlers_test.go"], + embed = [":go_default_library"], + deps = [ + "//beacon-chain/blockchain/testing:go_default_library", + "//beacon-chain/core/altair:go_default_library", + "//beacon-chain/core/signing:go_default_library", + "//beacon-chain/rpc/testutil:go_default_library", + "//beacon-chain/state/stategen/mock:go_default_library", + "//config/fieldparams:go_default_library", + "//config/params:go_default_library", + "//consensus-types/blocks:go_default_library", + "//consensus-types/interfaces:go_default_library", + "//consensus-types/primitives:go_default_library", + "//crypto/bls:go_default_library", + "//crypto/bls/blst:go_default_library", + "//encoding/bytesutil:go_default_library", + "//network:go_default_library", + "//proto/prysm/v1alpha1:go_default_library", + "//testing/assert:go_default_library", + "//testing/require:go_default_library", + "//testing/util:go_default_library", + "@com_github_prysmaticlabs_go_bitfield//:go_default_library", + ], +) diff --git a/beacon-chain/rpc/eth/rewards/handlers.go b/beacon-chain/rpc/eth/rewards/handlers.go new file mode 100644 index 000000000000..ff1fccb84e54 --- /dev/null +++ b/beacon-chain/rpc/eth/rewards/handlers.go @@ -0,0 +1,189 @@ +package rewards + +import ( + "net/http" + "strconv" + "strings" + + "github.com/pkg/errors" + "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/altair" + coreblocks "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/blocks" + "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/validators" + "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup" + "github.com/prysmaticlabs/prysm/v4/consensus-types/blocks" + "github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces" + "github.com/prysmaticlabs/prysm/v4/network" + "github.com/prysmaticlabs/prysm/v4/runtime/version" +) + +// BlockRewards is an HTTP handler for Beacon API getBlockRewards. +func (s *Server) BlockRewards(w http.ResponseWriter, r *http.Request) { + segments := strings.Split(r.URL.Path, "/") + blockId := segments[len(segments)-1] + + blk, err := s.Blocker.Block(r.Context(), []byte(blockId)) + if errJson := handleGetBlockError(blk, err); errJson != nil { + network.WriteError(w, errJson) + return + } + if blk.Version() == version.Phase0 { + errJson := &network.DefaultErrorJson{ + Message: "block rewards are not supported for Phase 0 blocks", + Code: http.StatusBadRequest, + } + network.WriteError(w, errJson) + return + } + + // We want to run several block processing functions that update the proposer's balance. + // This will allow us to calculate proposer rewards for each operation (atts, slashings etc). + // To do this, we replay the state up to the block's slot, but before processing the block. + st, err := s.ReplayerBuilder.ReplayerForSlot(blk.Block().Slot()-1).ReplayToSlot(r.Context(), blk.Block().Slot()) + if err != nil { + errJson := &network.DefaultErrorJson{ + Message: errors.Wrapf(err, "could not get state").Error(), + Code: http.StatusInternalServerError, + } + network.WriteError(w, errJson) + return + } + + proposerIndex := blk.Block().ProposerIndex() + initBalance, err := st.BalanceAtIndex(proposerIndex) + if err != nil { + errJson := &network.DefaultErrorJson{ + Message: errors.Wrapf(err, "could not get proposer's balance").Error(), + Code: http.StatusInternalServerError, + } + network.WriteError(w, errJson) + return + } + st, err = altair.ProcessAttestationsNoVerifySignature(r.Context(), st, blk) + if err != nil { + errJson := &network.DefaultErrorJson{ + Message: errors.Wrapf(err, "could not get attestation rewards").Error(), + Code: http.StatusInternalServerError, + } + network.WriteError(w, errJson) + return + } + attBalance, err := st.BalanceAtIndex(proposerIndex) + if err != nil { + errJson := &network.DefaultErrorJson{ + Message: errors.Wrapf(err, "could not get proposer's balance").Error(), + Code: http.StatusInternalServerError, + } + network.WriteError(w, errJson) + return + } + st, err = coreblocks.ProcessAttesterSlashings(r.Context(), st, blk.Block().Body().AttesterSlashings(), validators.SlashValidator) + if err != nil { + errJson := &network.DefaultErrorJson{ + Message: errors.Wrapf(err, "could not get attester slashing rewards").Error(), + Code: http.StatusInternalServerError, + } + network.WriteError(w, errJson) + return + } + attSlashingsBalance, err := st.BalanceAtIndex(proposerIndex) + if err != nil { + errJson := &network.DefaultErrorJson{ + Message: errors.Wrapf(err, "could not get proposer's balance").Error(), + Code: http.StatusInternalServerError, + } + network.WriteError(w, errJson) + return + } + st, err = coreblocks.ProcessProposerSlashings(r.Context(), st, blk.Block().Body().ProposerSlashings(), validators.SlashValidator) + if err != nil { + errJson := &network.DefaultErrorJson{ + Message: errors.Wrapf(err, "could not get proposer slashing rewards").Error(), + Code: http.StatusInternalServerError, + } + network.WriteError(w, errJson) + return + } + proposerSlashingsBalance, err := st.BalanceAtIndex(proposerIndex) + if err != nil { + errJson := &network.DefaultErrorJson{ + Message: errors.Wrapf(err, "could not get proposer's balance").Error(), + Code: http.StatusInternalServerError, + } + network.WriteError(w, errJson) + return + } + sa, err := blk.Block().Body().SyncAggregate() + if err != nil { + errJson := &network.DefaultErrorJson{ + Message: errors.Wrapf(err, "could not get sync aggregate").Error(), + Code: http.StatusInternalServerError, + } + network.WriteError(w, errJson) + return + } + var syncCommitteeReward uint64 + _, syncCommitteeReward, err = altair.ProcessSyncAggregate(r.Context(), st, sa) + if err != nil { + errJson := &network.DefaultErrorJson{ + Message: errors.Wrapf(err, "could not get sync aggregate rewards").Error(), + Code: http.StatusInternalServerError, + } + network.WriteError(w, errJson) + return + } + + optimistic, err := s.OptimisticModeFetcher.IsOptimistic(r.Context()) + if err != nil { + errJson := &network.DefaultErrorJson{ + Message: errors.Wrapf(err, "could not get optimistic mode info").Error(), + Code: http.StatusInternalServerError, + } + network.WriteError(w, errJson) + return + } + blkRoot, err := blk.Block().HashTreeRoot() + if err != nil { + errJson := &network.DefaultErrorJson{ + Message: errors.Wrapf(err, "could not get block root").Error(), + Code: http.StatusInternalServerError, + } + network.WriteError(w, errJson) + return + } + + response := &BlockRewardsResponse{ + Data: &BlockRewards{ + ProposerIndex: strconv.FormatUint(uint64(proposerIndex), 10), + Total: strconv.FormatUint(proposerSlashingsBalance-initBalance+syncCommitteeReward, 10), + Attestations: strconv.FormatUint(attBalance-initBalance, 10), + SyncAggregate: strconv.FormatUint(syncCommitteeReward, 10), + ProposerSlashings: strconv.FormatUint(proposerSlashingsBalance-attSlashingsBalance, 10), + AttesterSlashings: strconv.FormatUint(attSlashingsBalance-attBalance, 10), + }, + ExecutionOptimistic: optimistic, + Finalized: s.FinalizationFetcher.IsFinalized(r.Context(), blkRoot), + } + network.WriteJson(w, response) +} + +func handleGetBlockError(blk interfaces.ReadOnlySignedBeaconBlock, err error) *network.DefaultErrorJson { + if errors.Is(err, lookup.BlockIdParseError{}) { + return &network.DefaultErrorJson{ + Message: errors.Wrapf(err, "invalid block ID").Error(), + Code: http.StatusBadRequest, + } + } + if err != nil { + return &network.DefaultErrorJson{ + Message: errors.Wrapf(err, "could not get block from block ID").Error(), + Code: http.StatusInternalServerError, + } + } + if err := blocks.BeaconBlockIsNil(blk); err != nil { + return &network.DefaultErrorJson{ + Message: errors.Wrapf(err, "could not find requested block").Error(), + Code: http.StatusNotFound, + } + } + return nil +} diff --git a/beacon-chain/rpc/eth/rewards/handlers_test.go b/beacon-chain/rpc/eth/rewards/handlers_test.go new file mode 100644 index 000000000000..25a0464aa051 --- /dev/null +++ b/beacon-chain/rpc/eth/rewards/handlers_test.go @@ -0,0 +1,198 @@ +package rewards + +import ( + "bytes" + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + + "github.com/prysmaticlabs/go-bitfield" + mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing" + "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/altair" + "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/signing" + "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/testutil" + mockstategen "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen/mock" + fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams" + "github.com/prysmaticlabs/prysm/v4/config/params" + "github.com/prysmaticlabs/prysm/v4/consensus-types/blocks" + "github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces" + "github.com/prysmaticlabs/prysm/v4/consensus-types/primitives" + "github.com/prysmaticlabs/prysm/v4/crypto/bls" + "github.com/prysmaticlabs/prysm/v4/crypto/bls/blst" + "github.com/prysmaticlabs/prysm/v4/encoding/bytesutil" + "github.com/prysmaticlabs/prysm/v4/network" + eth "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/prysm/v4/testing/assert" + "github.com/prysmaticlabs/prysm/v4/testing/require" + "github.com/prysmaticlabs/prysm/v4/testing/util" +) + +func TestBlockRewards(t *testing.T) { + valCount := 64 + + st, err := util.NewBeaconStateAltair() + require.NoError(t, st.SetSlot(1)) + require.NoError(t, err) + validators := make([]*eth.Validator, 0, valCount) + balances := make([]uint64, 0, valCount) + secretKeys := make([]bls.SecretKey, 0, valCount) + for i := 0; i < valCount; i++ { + blsKey, err := bls.RandKey() + require.NoError(t, err) + secretKeys = append(secretKeys, blsKey) + validators = append(validators, ð.Validator{ + PublicKey: blsKey.PublicKey().Marshal(), + ExitEpoch: params.BeaconConfig().FarFutureEpoch, + WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch, + EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance, + }) + balances = append(balances, params.BeaconConfig().MaxEffectiveBalance) + } + require.NoError(t, st.SetValidators(validators)) + require.NoError(t, st.SetBalances(balances)) + require.NoError(t, st.SetCurrentParticipationBits(make([]byte, valCount))) + syncCommittee, err := altair.NextSyncCommittee(context.Background(), st) + require.NoError(t, err) + require.NoError(t, st.SetCurrentSyncCommittee(syncCommittee)) + slot0bRoot := bytesutil.PadTo([]byte("slot0root"), 32) + bRoots := make([][]byte, fieldparams.BlockRootsLength) + bRoots[0] = slot0bRoot + require.NoError(t, st.SetBlockRoots(bRoots)) + + b := util.HydrateSignedBeaconBlockAltair(util.NewBeaconBlockAltair()) + b.Block.Slot = 2 + // we have to set the proposer index to the value that will be randomly chosen (fortunately it's deterministic) + b.Block.ProposerIndex = 12 + b.Block.Body.Attestations = []*eth.Attestation{ + { + AggregationBits: bitfield.Bitlist{0b00000111}, + Data: util.HydrateAttestationData(ð.AttestationData{}), + Signature: make([]byte, fieldparams.BLSSignatureLength), + }, + { + AggregationBits: bitfield.Bitlist{0b00000111}, + Data: util.HydrateAttestationData(ð.AttestationData{}), + Signature: make([]byte, fieldparams.BLSSignatureLength), + }, + } + attData1 := util.HydrateAttestationData(ð.AttestationData{BeaconBlockRoot: bytesutil.PadTo([]byte("root1"), 32)}) + attData2 := util.HydrateAttestationData(ð.AttestationData{BeaconBlockRoot: bytesutil.PadTo([]byte("root2"), 32)}) + domain, err := signing.Domain(st.Fork(), 0, params.BeaconConfig().DomainBeaconAttester, st.GenesisValidatorsRoot()) + require.NoError(t, err) + sigRoot1, err := signing.ComputeSigningRoot(attData1, domain) + require.NoError(t, err) + sigRoot2, err := signing.ComputeSigningRoot(attData2, domain) + require.NoError(t, err) + b.Block.Body.AttesterSlashings = []*eth.AttesterSlashing{ + { + Attestation_1: ð.IndexedAttestation{ + AttestingIndices: []uint64{0}, + Data: attData1, + Signature: secretKeys[0].Sign(sigRoot1[:]).Marshal(), + }, + Attestation_2: ð.IndexedAttestation{ + AttestingIndices: []uint64{0}, + Data: attData2, + Signature: secretKeys[0].Sign(sigRoot2[:]).Marshal(), + }, + }, + } + header1 := ð.BeaconBlockHeader{ + Slot: 0, + ProposerIndex: 1, + ParentRoot: bytesutil.PadTo([]byte("root1"), 32), + StateRoot: bytesutil.PadTo([]byte("root1"), 32), + BodyRoot: bytesutil.PadTo([]byte("root1"), 32), + } + header2 := ð.BeaconBlockHeader{ + Slot: 0, + ProposerIndex: 1, + ParentRoot: bytesutil.PadTo([]byte("root2"), 32), + StateRoot: bytesutil.PadTo([]byte("root2"), 32), + BodyRoot: bytesutil.PadTo([]byte("root2"), 32), + } + domain, err = signing.Domain(st.Fork(), 0, params.BeaconConfig().DomainBeaconProposer, st.GenesisValidatorsRoot()) + require.NoError(t, err) + sigRoot1, err = signing.ComputeSigningRoot(header1, domain) + require.NoError(t, err) + sigRoot2, err = signing.ComputeSigningRoot(header2, domain) + require.NoError(t, err) + b.Block.Body.ProposerSlashings = []*eth.ProposerSlashing{ + { + Header_1: ð.SignedBeaconBlockHeader{ + Header: header1, + Signature: secretKeys[1].Sign(sigRoot1[:]).Marshal(), + }, + Header_2: ð.SignedBeaconBlockHeader{ + Header: header2, + Signature: secretKeys[1].Sign(sigRoot2[:]).Marshal(), + }, + }, + } + scBits := bitfield.NewBitvector512() + scBits.SetBitAt(10, true) + scBits.SetBitAt(100, true) + domain, err = signing.Domain(st.Fork(), 0, params.BeaconConfig().DomainSyncCommittee, st.GenesisValidatorsRoot()) + require.NoError(t, err) + sszBytes := primitives.SSZBytes(slot0bRoot) + r, err := signing.ComputeSigningRoot(&sszBytes, domain) + require.NoError(t, err) + // Bits set in sync committee bits determine which validators will be treated as participating in sync committee. + // These validators have to sign the message. + sig1, err := blst.SignatureFromBytes(secretKeys[47].Sign(r[:]).Marshal()) + require.NoError(t, err) + sig2, err := blst.SignatureFromBytes(secretKeys[19].Sign(r[:]).Marshal()) + require.NoError(t, err) + aggSig := bls.AggregateSignatures([]bls.Signature{sig1, sig2}).Marshal() + b.Block.Body.SyncAggregate = ð.SyncAggregate{SyncCommitteeBits: scBits, SyncCommitteeSignature: aggSig} + + sbb, err := blocks.NewSignedBeaconBlock(b) + require.NoError(t, err) + phase0block, err := blocks.NewSignedBeaconBlock(util.NewBeaconBlock()) + require.NoError(t, err) + mockChainService := &mock.ChainService{Optimistic: true} + s := &Server{ + Blocker: &testutil.MockBlocker{SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{ + 0: phase0block, + 2: sbb, + }}, + OptimisticModeFetcher: mockChainService, + FinalizationFetcher: mockChainService, + ReplayerBuilder: mockstategen.NewMockReplayerBuilder(mockstategen.WithMockState(st)), + } + + t.Run("ok", func(t *testing.T) { + url := "http://only.the.slot.number.at.the.end.is.important/2" + request := httptest.NewRequest("GET", url, nil) + writer := httptest.NewRecorder() + writer.Body = &bytes.Buffer{} + + s.BlockRewards(writer, request) + assert.Equal(t, http.StatusOK, writer.Code) + resp := &BlockRewardsResponse{} + require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp)) + assert.Equal(t, "12", resp.Data.ProposerIndex) + assert.Equal(t, "125089490", resp.Data.Total) + assert.Equal(t, "89442", resp.Data.Attestations) + assert.Equal(t, "48", resp.Data.SyncAggregate) + assert.Equal(t, "62500000", resp.Data.AttesterSlashings) + assert.Equal(t, "62500000", resp.Data.ProposerSlashings) + assert.Equal(t, true, resp.ExecutionOptimistic) + assert.Equal(t, false, resp.Finalized) + }) + t.Run("phase 0", func(t *testing.T) { + url := "http://only.the.slot.number.at.the.end.is.important/0" + request := httptest.NewRequest("GET", url, nil) + writer := httptest.NewRecorder() + writer.Body = &bytes.Buffer{} + + s.BlockRewards(writer, request) + assert.Equal(t, http.StatusBadRequest, writer.Code) + e := &network.DefaultErrorJson{} + require.NoError(t, json.Unmarshal(writer.Body.Bytes(), e)) + assert.Equal(t, http.StatusBadRequest, e.Code) + assert.Equal(t, "block rewards are not supported for Phase 0 blocks", e.Message) + }) +} diff --git a/beacon-chain/rpc/eth/rewards/server.go b/beacon-chain/rpc/eth/rewards/server.go new file mode 100644 index 000000000000..d1c11fce1983 --- /dev/null +++ b/beacon-chain/rpc/eth/rewards/server.go @@ -0,0 +1,14 @@ +package rewards + +import ( + "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain" + "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup" + "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen" +) + +type Server struct { + Blocker lookup.Blocker + OptimisticModeFetcher blockchain.OptimisticModeFetcher + FinalizationFetcher blockchain.FinalizationFetcher + ReplayerBuilder stategen.ReplayerBuilder +} diff --git a/beacon-chain/rpc/eth/rewards/structs.go b/beacon-chain/rpc/eth/rewards/structs.go new file mode 100644 index 000000000000..924e6023a380 --- /dev/null +++ b/beacon-chain/rpc/eth/rewards/structs.go @@ -0,0 +1,16 @@ +package rewards + +type BlockRewardsResponse struct { + Data *BlockRewards `json:"data"` + ExecutionOptimistic bool `json:"execution_optimistic"` + Finalized bool `json:"finalized"` +} + +type BlockRewards struct { + ProposerIndex string `json:"proposer_index"` + Total string `json:"total"` + Attestations string `json:"attestations"` + SyncAggregate string `json:"sync_aggregate"` + ProposerSlashings string `json:"proposer_slashings"` + AttesterSlashings string `json:"attester_slashings"` +} diff --git a/beacon-chain/rpc/eth/validator/BUILD.bazel b/beacon-chain/rpc/eth/validator/BUILD.bazel index 185c7b05ee3a..d82a26cf06a6 100644 --- a/beacon-chain/rpc/eth/validator/BUILD.bazel +++ b/beacon-chain/rpc/eth/validator/BUILD.bazel @@ -19,8 +19,8 @@ go_library( "//beacon-chain/operations/synccommittee:go_default_library", "//beacon-chain/p2p:go_default_library", "//beacon-chain/rpc/eth/helpers:go_default_library", + "//beacon-chain/rpc/lookup:go_default_library", "//beacon-chain/rpc/prysm/v1alpha1/validator:go_default_library", - "//beacon-chain/rpc/statefetcher:go_default_library", "//beacon-chain/state:go_default_library", "//beacon-chain/state/state-native:go_default_library", "//beacon-chain/sync:go_default_library", diff --git a/beacon-chain/rpc/eth/validator/server.go b/beacon-chain/rpc/eth/validator/server.go index c34af40a0c8c..ca3592284058 100644 --- a/beacon-chain/rpc/eth/validator/server.go +++ b/beacon-chain/rpc/eth/validator/server.go @@ -7,8 +7,8 @@ import ( "github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/attestations" "github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/synccommittee" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p" + "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup" v1alpha1validator "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/prysm/v1alpha1/validator" - "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/statefetcher" "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync" ) @@ -21,7 +21,7 @@ type Server struct { AttestationsPool attestations.Pool PeerManager p2p.PeerManager Broadcaster p2p.Broadcaster - StateFetcher statefetcher.Fetcher + Stater lookup.Stater OptimisticModeFetcher blockchain.OptimisticModeFetcher SyncCommitteePool synccommittee.Pool V1Alpha1Server *v1alpha1validator.Server diff --git a/beacon-chain/rpc/eth/validator/validator.go b/beacon-chain/rpc/eth/validator/validator.go index 5e4126d538b2..fd53e41e571f 100644 --- a/beacon-chain/rpc/eth/validator/validator.go +++ b/beacon-chain/rpc/eth/validator/validator.go @@ -70,7 +70,7 @@ func (vs *Server) GetAttesterDuties(ctx context.Context, req *ethpbv1.AttesterDu return nil, status.Errorf(codes.Internal, "Could not get start slot from epoch %d: %v", req.Epoch, err) } - s, err := vs.StateFetcher.StateBySlot(ctx, startSlot) + s, err := vs.Stater.StateBySlot(ctx, startSlot) if err != nil { return nil, status.Errorf(codes.Internal, "Could not get state: %v", err) } @@ -159,7 +159,7 @@ func (vs *Server) GetProposerDuties(ctx context.Context, req *ethpbv1.ProposerDu if err != nil { return nil, status.Errorf(codes.Internal, "Could not get start slot from epoch %d: %v", req.Epoch, err) } - s, err := vs.StateFetcher.StateBySlot(ctx, startSlot) + s, err := vs.Stater.StateBySlot(ctx, startSlot) if err != nil { return nil, status.Errorf(codes.Internal, "Could not get state: %v", err) } @@ -243,7 +243,7 @@ func (vs *Server) GetSyncCommitteeDuties(ctx context.Context, req *ethpbv2.SyncC if err != nil { return nil, status.Errorf(codes.Internal, "Could not get sync committee slot: %v", err) } - st, err := vs.StateFetcher.State(ctx, []byte(strconv.FormatUint(uint64(slot), 10))) + st, err := vs.Stater.State(ctx, []byte(strconv.FormatUint(uint64(slot), 10))) if err != nil { return nil, status.Errorf(codes.Internal, "Could not get sync committee state: %v", err) } @@ -282,7 +282,7 @@ func (vs *Server) GetSyncCommitteeDuties(ctx context.Context, req *ethpbv2.SyncC ctx, []byte(strconv.FormatUint(uint64(slot), 10)), vs.OptimisticModeFetcher, - vs.StateFetcher, + vs.Stater, vs.ChainInfoFetcher, vs.BeaconDB, ) @@ -1081,7 +1081,7 @@ func (vs *Server) GetLiveness(ctx context.Context, req *ethpbv2.GetLivenessReque if err != nil { return nil, status.Error(codes.Internal, "Could not get requested epoch's end slot") } - st, err = vs.StateFetcher.StateBySlot(ctx, epochEnd) + st, err = vs.Stater.StateBySlot(ctx, epochEnd) if err != nil { return nil, status.Error(codes.Internal, "Could not get slot for requested epoch") } diff --git a/beacon-chain/rpc/eth/validator/validator_test.go b/beacon-chain/rpc/eth/validator/validator_test.go index d85edd01c642..d502794a61af 100644 --- a/beacon-chain/rpc/eth/validator/validator_test.go +++ b/beacon-chain/rpc/eth/validator/validator_test.go @@ -93,7 +93,7 @@ func TestGetAttesterDuties(t *testing.T) { State: bs, Root: genesisRoot[:], Slot: &chainSlot, } vs := &Server{ - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ StatesBySlot: map[primitives.Slot]state.BeaconState{ 0: bs, params.BeaconConfig().SlotsPerEpoch: nextEpochState, @@ -198,7 +198,7 @@ func TestGetAttesterDuties(t *testing.T) { State: bs, Root: genesisRoot[:], Slot: &chainSlot, Optimistic: true, } vs := &Server{ - StateFetcher: &testutil.MockFetcher{StatesBySlot: map[primitives.Slot]state.BeaconState{0: bs}}, + Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{0: bs}}, TimeFetcher: chain, OptimisticModeFetcher: chain, SyncChecker: &mockSync.Sync{IsSyncing: false}, @@ -258,7 +258,7 @@ func TestGetProposerDuties(t *testing.T) { State: bs, Root: genesisRoot[:], Slot: &chainSlot, } vs := &Server{ - StateFetcher: &testutil.MockFetcher{StatesBySlot: map[primitives.Slot]state.BeaconState{0: bs}}, + Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{0: bs}}, HeadFetcher: chain, TimeFetcher: chain, OptimisticModeFetcher: chain, @@ -297,7 +297,7 @@ func TestGetProposerDuties(t *testing.T) { State: bs, Root: genesisRoot[:], Slot: &chainSlot, } vs := &Server{ - StateFetcher: &testutil.MockFetcher{StatesBySlot: map[primitives.Slot]state.BeaconState{0: bs}}, + Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{0: bs}}, HeadFetcher: chain, TimeFetcher: chain, OptimisticModeFetcher: chain, @@ -337,7 +337,7 @@ func TestGetProposerDuties(t *testing.T) { State: bs, Root: genesisRoot[:], Slot: &chainSlot, } vs := &Server{ - StateFetcher: &testutil.MockFetcher{StatesBySlot: map[primitives.Slot]state.BeaconState{params.BeaconConfig().SlotsPerEpoch: bs}}, + Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{params.BeaconConfig().SlotsPerEpoch: bs}}, HeadFetcher: chain, TimeFetcher: chain, OptimisticModeFetcher: chain, @@ -377,7 +377,7 @@ func TestGetProposerDuties(t *testing.T) { State: bs, Root: genesisRoot[:], Slot: &chainSlot, } vs := &Server{ - StateFetcher: &testutil.MockFetcher{StatesBySlot: map[primitives.Slot]state.BeaconState{0: bs}}, + Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{0: bs}}, HeadFetcher: chain, TimeFetcher: chain, OptimisticModeFetcher: chain, @@ -414,7 +414,7 @@ func TestGetProposerDuties(t *testing.T) { State: bs, Root: genesisRoot[:], Slot: &chainSlot, Optimistic: true, } vs := &Server{ - StateFetcher: &testutil.MockFetcher{StatesBySlot: map[primitives.Slot]state.BeaconState{0: bs}}, + Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{0: bs}}, HeadFetcher: chain, TimeFetcher: chain, OptimisticModeFetcher: chain, @@ -469,7 +469,7 @@ func TestGetSyncCommitteeDuties(t *testing.T) { mockChainService := &mockChain.ChainService{Genesis: genesisTime} vs := &Server{ - StateFetcher: &testutil.MockFetcher{BeaconState: st}, + Stater: &testutil.MockStater{BeaconState: st}, SyncChecker: &mockSync.Sync{IsSyncing: false}, TimeFetcher: mockChainService, HeadFetcher: mockChainService, @@ -611,7 +611,7 @@ func TestGetSyncCommitteeDuties(t *testing.T) { } mockChainService := &mockChain.ChainService{Genesis: genesisTime, Slot: &newSyncPeriodStartSlot} vs := &Server{ - StateFetcher: &testutil.MockFetcher{BeaconState: stateFetchFn(newSyncPeriodStartSlot)}, + Stater: &testutil.MockStater{BeaconState: stateFetchFn(newSyncPeriodStartSlot)}, SyncChecker: &mockSync.Sync{IsSyncing: false}, TimeFetcher: mockChainService, HeadFetcher: mockChainService, @@ -665,7 +665,7 @@ func TestGetSyncCommitteeDuties(t *testing.T) { State: state, } vs := &Server{ - StateFetcher: &testutil.MockFetcher{BeaconState: st}, + Stater: &testutil.MockStater{BeaconState: st}, SyncChecker: &mockSync.Sync{IsSyncing: false}, TimeFetcher: mockChainService, HeadFetcher: mockChainService, @@ -5021,7 +5021,7 @@ func TestGetLiveness(t *testing.T) { server := &Server{ HeadFetcher: &mockChain.ChainService{State: headSt}, - StateFetcher: &testutil.MockFetcher{ + Stater: &testutil.MockStater{ // We configure states for last slots of an epoch StatesBySlot: map[primitives.Slot]state.BeaconState{ params.BeaconConfig().SlotsPerEpoch - 1: oldSt, diff --git a/beacon-chain/rpc/statefetcher/BUILD.bazel b/beacon-chain/rpc/lookup/BUILD.bazel similarity index 84% rename from beacon-chain/rpc/statefetcher/BUILD.bazel rename to beacon-chain/rpc/lookup/BUILD.bazel index 84490038468e..4b39e7657206 100644 --- a/beacon-chain/rpc/statefetcher/BUILD.bazel +++ b/beacon-chain/rpc/lookup/BUILD.bazel @@ -2,9 +2,12 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test") go_library( name = "go_default_library", - srcs = ["fetcher.go"], - importpath = "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/statefetcher", - visibility = ["//beacon-chain:__subpackages__"], + srcs = [ + "blocker.go", + "stater.go", + ], + importpath = "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup", + visibility = ["//visibility:public"], deps = [ "//beacon-chain/blockchain:go_default_library", "//beacon-chain/db:go_default_library", @@ -12,6 +15,7 @@ go_library( "//beacon-chain/state/stategen:go_default_library", "//config/params:go_default_library", "//consensus-types/blocks:go_default_library", + "//consensus-types/interfaces:go_default_library", "//consensus-types/primitives:go_default_library", "//encoding/bytesutil:go_default_library", "//time/slots:go_default_library", @@ -22,11 +26,15 @@ go_library( go_test( name = "go_default_test", - srcs = ["fetcher_test.go"], + srcs = [ + "blocker_test.go", + "stater_test.go", + ], embed = [":go_default_library"], deps = [ "//beacon-chain/blockchain/testing:go_default_library", "//beacon-chain/db/testing:go_default_library", + "//beacon-chain/rpc/testutil:go_default_library", "//beacon-chain/state/state-native:go_default_library", "//beacon-chain/state/stategen:go_default_library", "//beacon-chain/state/stategen/mock:go_default_library", diff --git a/beacon-chain/rpc/lookup/blocker.go b/beacon-chain/rpc/lookup/blocker.go new file mode 100644 index 000000000000..46bb84610b55 --- /dev/null +++ b/beacon-chain/rpc/lookup/blocker.go @@ -0,0 +1,108 @@ +package lookup + +import ( + "context" + "strconv" + + "github.com/pkg/errors" + "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain" + "github.com/prysmaticlabs/prysm/v4/beacon-chain/db" + "github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces" + "github.com/prysmaticlabs/prysm/v4/consensus-types/primitives" + "github.com/prysmaticlabs/prysm/v4/encoding/bytesutil" +) + +// BlockIdParseError represents an error scenario where a block ID could not be parsed. +type BlockIdParseError struct { + message string +} + +// NewBlockIdParseError creates a new error instance. +func NewBlockIdParseError(reason error) BlockIdParseError { + return BlockIdParseError{ + message: errors.Wrapf(reason, "could not parse block ID").Error(), + } +} + +// Error returns the underlying error message. +func (e BlockIdParseError) Error() string { + return e.message +} + +// Blocker is responsible for retrieving blocks. +type Blocker interface { + Block(ctx context.Context, id []byte) (interfaces.ReadOnlySignedBeaconBlock, error) +} + +// BeaconDbBlocker is an implementation of Blocker. It retrieves blocks from the beacon chain database. +type BeaconDbBlocker struct { + BeaconDB db.ReadOnlyDatabase + ChainInfoFetcher blockchain.ChainInfoFetcher +} + +// Block returns the beacon block for a given identifier. The identifier can be one of: +// - "head" (canonical head in node's view) +// - "genesis" +// - "finalized" +// - "justified" +// - +// - +func (p *BeaconDbBlocker) Block(ctx context.Context, id []byte) (interfaces.ReadOnlySignedBeaconBlock, error) { + var err error + var blk interfaces.ReadOnlySignedBeaconBlock + switch string(id) { + case "head": + blk, err = p.ChainInfoFetcher.HeadBlock(ctx) + if err != nil { + return nil, errors.Wrap(err, "could not retrieve head block") + } + case "finalized": + finalized := p.ChainInfoFetcher.FinalizedCheckpt() + finalizedRoot := bytesutil.ToBytes32(finalized.Root) + blk, err = p.BeaconDB.Block(ctx, finalizedRoot) + if err != nil { + return nil, errors.New("could not get finalized block from db") + } + case "genesis": + blk, err = p.BeaconDB.GenesisBlock(ctx) + if err != nil { + return nil, errors.Wrap(err, "could not retrieve genesis block") + } + default: + if len(id) == 32 { + blk, err = p.BeaconDB.Block(ctx, bytesutil.ToBytes32(id)) + if err != nil { + return nil, errors.Wrap(err, "could not retrieve block") + } + } else { + slot, err := strconv.ParseUint(string(id), 10, 64) + if err != nil { + e := NewBlockIdParseError(err) + return nil, &e + } + blks, err := p.BeaconDB.BlocksBySlot(ctx, primitives.Slot(slot)) + if err != nil { + return nil, errors.Wrapf(err, "could not retrieve blocks for slot %d", slot) + } + _, roots, err := p.BeaconDB.BlockRootsBySlot(ctx, primitives.Slot(slot)) + if err != nil { + return nil, errors.Wrapf(err, "could not retrieve block roots for slot %d", slot) + } + numBlks := len(blks) + if numBlks == 0 { + return nil, nil + } + for i, b := range blks { + canonical, err := p.ChainInfoFetcher.IsCanonical(ctx, roots[i]) + if err != nil { + return nil, errors.Wrapf(err, "could not determine if block root is canonical") + } + if canonical { + blk = b + break + } + } + } + } + return blk, nil +} diff --git a/beacon-chain/rpc/lookup/blocker_test.go b/beacon-chain/rpc/lookup/blocker_test.go new file mode 100644 index 000000000000..4cf55e35a6e7 --- /dev/null +++ b/beacon-chain/rpc/lookup/blocker_test.go @@ -0,0 +1,144 @@ +package lookup + +import ( + "context" + "fmt" + "reflect" + "testing" + + mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing" + dbtesting "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing" + "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/testutil" + "github.com/prysmaticlabs/prysm/v4/consensus-types/blocks" + "github.com/prysmaticlabs/prysm/v4/encoding/bytesutil" + ethpbalpha "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/prysm/v4/testing/assert" + "github.com/prysmaticlabs/prysm/v4/testing/require" + "github.com/prysmaticlabs/prysm/v4/testing/util" +) + +func TestGetBlock(t *testing.T) { + beaconDB := dbtesting.SetupDB(t) + ctx := context.Background() + + genBlk, blkContainers := testutil.FillDBWithBlocks(ctx, t, beaconDB) + canonicalRoots := make(map[[32]byte]bool) + + for _, bContr := range blkContainers { + canonicalRoots[bytesutil.ToBytes32(bContr.BlockRoot)] = true + } + headBlock := blkContainers[len(blkContainers)-1] + nextSlot := headBlock.GetPhase0Block().Block.Slot + 1 + + b2 := util.NewBeaconBlock() + b2.Block.Slot = 30 + b2.Block.ParentRoot = bytesutil.PadTo([]byte{1}, 32) + util.SaveBlock(t, ctx, beaconDB, b2) + b3 := util.NewBeaconBlock() + b3.Block.Slot = 30 + b3.Block.ParentRoot = bytesutil.PadTo([]byte{4}, 32) + util.SaveBlock(t, ctx, beaconDB, b3) + b4 := util.NewBeaconBlock() + b4.Block.Slot = nextSlot + b4.Block.ParentRoot = bytesutil.PadTo([]byte{8}, 32) + util.SaveBlock(t, ctx, beaconDB, b4) + + wsb, err := blocks.NewSignedBeaconBlock(headBlock.Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block) + require.NoError(t, err) + + fetcher := &BeaconDbBlocker{ + BeaconDB: beaconDB, + ChainInfoFetcher: &mock.ChainService{ + DB: beaconDB, + Block: wsb, + Root: headBlock.BlockRoot, + FinalizedCheckPoint: ðpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot}, + CanonicalRoots: canonicalRoots, + }, + } + + root, err := genBlk.Block.HashTreeRoot() + require.NoError(t, err) + + tests := []struct { + name string + blockID []byte + want *ethpbalpha.SignedBeaconBlock + wantErr bool + }{ + { + name: "slot", + blockID: []byte("30"), + want: blkContainers[30].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block, + }, + { + name: "bad formatting", + blockID: []byte("3bad0"), + wantErr: true, + }, + { + name: "canonical", + blockID: []byte("30"), + want: blkContainers[30].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block, + }, + { + name: "non canonical", + blockID: []byte(fmt.Sprintf("%d", nextSlot)), + want: nil, + }, + { + name: "head", + blockID: []byte("head"), + want: headBlock.Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block, + }, + { + name: "finalized", + blockID: []byte("finalized"), + want: blkContainers[64].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block, + }, + { + name: "genesis", + blockID: []byte("genesis"), + want: genBlk, + }, + { + name: "genesis root", + blockID: root[:], + want: genBlk, + }, + { + name: "root", + blockID: blkContainers[20].BlockRoot, + want: blkContainers[20].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block, + }, + { + name: "non-existent root", + blockID: bytesutil.PadTo([]byte("hi there"), 32), + want: nil, + }, + { + name: "no block", + blockID: []byte("105"), + want: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := fetcher.Block(ctx, tt.blockID) + if tt.wantErr { + assert.NotEqual(t, err, nil, "no error has been returned") + return + } + if tt.want == nil { + assert.Equal(t, nil, result) + return + } + require.NoError(t, err) + pbBlock, err := result.PbPhase0Block() + require.NoError(t, err) + if !reflect.DeepEqual(pbBlock, tt.want) { + t.Error("Expected blocks to equal") + } + }) + } +} diff --git a/beacon-chain/rpc/statefetcher/fetcher.go b/beacon-chain/rpc/lookup/stater.go similarity index 87% rename from beacon-chain/rpc/statefetcher/fetcher.go rename to beacon-chain/rpc/lookup/stater.go index 0a4019dee3bf..6da0e1a2d7a7 100644 --- a/beacon-chain/rpc/statefetcher/fetcher.go +++ b/beacon-chain/rpc/lookup/stater.go @@ -1,4 +1,4 @@ -package statefetcher +package lookup import ( "bytes" @@ -71,15 +71,15 @@ func (e *StateRootNotFoundError) Error() string { return e.message } -// Fetcher is responsible for retrieving info related with the beacon chain. -type Fetcher interface { - State(ctx context.Context, stateId []byte) (state.BeaconState, error) - StateRoot(ctx context.Context, stateId []byte) ([]byte, error) +// Stater is responsible for retrieving states. +type Stater interface { + State(ctx context.Context, id []byte) (state.BeaconState, error) + StateRoot(ctx context.Context, id []byte) ([]byte, error) StateBySlot(ctx context.Context, slot primitives.Slot) (state.BeaconState, error) } -// StateProvider is a real implementation of Fetcher. -type StateProvider struct { +// BeaconDbStater is an implementation of Stater. It retrieves states from the beacon chain database. +type BeaconDbStater struct { BeaconDB db.ReadOnlyDatabase ChainInfoFetcher blockchain.ChainInfoFetcher GenesisTimeFetcher blockchain.TimeFetcher @@ -94,7 +94,7 @@ type StateProvider struct { // - "justified" // - // - -func (p *StateProvider) State(ctx context.Context, stateId []byte) (state.BeaconState, error) { +func (p *BeaconDbStater) State(ctx context.Context, stateId []byte) (state.BeaconState, error) { var ( s state.BeaconState err error @@ -164,7 +164,7 @@ func (p *StateProvider) State(ctx context.Context, stateId []byte) (state.Beacon // - "justified" // - // - -func (p *StateProvider) StateRoot(ctx context.Context, stateId []byte) (root []byte, err error) { +func (p *BeaconDbStater) StateRoot(ctx context.Context, stateId []byte) (root []byte, err error) { stateIdString := strings.ToLower(string(stateId)) switch stateIdString { case "head": @@ -192,7 +192,7 @@ func (p *StateProvider) StateRoot(ctx context.Context, stateId []byte) (root []b return root, err } -func (p *StateProvider) stateByRoot(ctx context.Context, stateRoot []byte) (state.BeaconState, error) { +func (p *BeaconDbStater) stateByRoot(ctx context.Context, stateRoot []byte) (state.BeaconState, error) { headState, err := p.ChainInfoFetcher.HeadStateReadOnly(ctx) if err != nil { return nil, errors.Wrap(err, "could not get head state") @@ -213,7 +213,7 @@ func (p *StateProvider) stateByRoot(ctx context.Context, stateRoot []byte) (stat // between the found state's slot and the target slot. // process_blocks is applied for all canonical blocks, and process_slots is called for any skipped // slots, or slots following the most recent canonical block up to and including the target slot. -func (p *StateProvider) StateBySlot(ctx context.Context, target primitives.Slot) (state.BeaconState, error) { +func (p *BeaconDbStater) StateBySlot(ctx context.Context, target primitives.Slot) (state.BeaconState, error) { ctx, span := trace.StartSpan(ctx, "statefetcher.StateBySlot") defer span.End() @@ -229,7 +229,7 @@ func (p *StateProvider) StateBySlot(ctx context.Context, target primitives.Slot) return st, nil } -func (p *StateProvider) headStateRoot(ctx context.Context) ([]byte, error) { +func (p *BeaconDbStater) headStateRoot(ctx context.Context) ([]byte, error) { b, err := p.ChainInfoFetcher.HeadBlock(ctx) if err != nil { return nil, errors.Wrap(err, "could not get head block") @@ -241,7 +241,7 @@ func (p *StateProvider) headStateRoot(ctx context.Context) ([]byte, error) { return stateRoot[:], nil } -func (p *StateProvider) genesisStateRoot(ctx context.Context) ([]byte, error) { +func (p *BeaconDbStater) genesisStateRoot(ctx context.Context) ([]byte, error) { b, err := p.BeaconDB.GenesisBlock(ctx) if err != nil { return nil, errors.Wrap(err, "could not get genesis block") @@ -253,7 +253,7 @@ func (p *StateProvider) genesisStateRoot(ctx context.Context) ([]byte, error) { return stateRoot[:], nil } -func (p *StateProvider) finalizedStateRoot(ctx context.Context) ([]byte, error) { +func (p *BeaconDbStater) finalizedStateRoot(ctx context.Context) ([]byte, error) { cp, err := p.BeaconDB.FinalizedCheckpoint(ctx) if err != nil { return nil, errors.Wrap(err, "could not get finalized checkpoint") @@ -269,7 +269,7 @@ func (p *StateProvider) finalizedStateRoot(ctx context.Context) ([]byte, error) return stateRoot[:], nil } -func (p *StateProvider) justifiedStateRoot(ctx context.Context) ([]byte, error) { +func (p *BeaconDbStater) justifiedStateRoot(ctx context.Context) ([]byte, error) { cp, err := p.BeaconDB.JustifiedCheckpoint(ctx) if err != nil { return nil, errors.Wrap(err, "could not get justified checkpoint") @@ -285,7 +285,7 @@ func (p *StateProvider) justifiedStateRoot(ctx context.Context) ([]byte, error) return stateRoot[:], nil } -func (p *StateProvider) stateRootByRoot(ctx context.Context, stateRoot []byte) ([]byte, error) { +func (p *BeaconDbStater) stateRootByRoot(ctx context.Context, stateRoot []byte) ([]byte, error) { var r [32]byte copy(r[:], stateRoot) headState, err := p.ChainInfoFetcher.HeadStateReadOnly(ctx) @@ -302,7 +302,7 @@ func (p *StateProvider) stateRootByRoot(ctx context.Context, stateRoot []byte) ( return nil, &rootNotFoundErr } -func (p *StateProvider) stateRootBySlot(ctx context.Context, slot primitives.Slot) ([]byte, error) { +func (p *BeaconDbStater) stateRootBySlot(ctx context.Context, slot primitives.Slot) ([]byte, error) { currentSlot := p.GenesisTimeFetcher.CurrentSlot() if slot > currentSlot { return nil, errors.New("slot cannot be in the future") diff --git a/beacon-chain/rpc/statefetcher/fetcher_test.go b/beacon-chain/rpc/lookup/stater_test.go similarity index 95% rename from beacon-chain/rpc/statefetcher/fetcher_test.go rename to beacon-chain/rpc/lookup/stater_test.go index 93eeca3ddc06..cc7ca07f4409 100644 --- a/beacon-chain/rpc/statefetcher/fetcher_test.go +++ b/beacon-chain/rpc/lookup/stater_test.go @@ -1,4 +1,4 @@ -package statefetcher +package lookup import ( "context" @@ -38,7 +38,7 @@ func TestGetState(t *testing.T) { require.NoError(t, err) t.Run("head", func(t *testing.T) { - p := StateProvider{ + p := BeaconDbStater{ ChainInfoFetcher: &chainMock.ChainService{State: newBeaconState}, } @@ -78,7 +78,7 @@ func TestGetState(t *testing.T) { cs := &mockstategen.MockCurrentSlotter{Slot: bs.Slot() + 1} ch := stategen.NewCanonicalHistory(db, cc, cs) currentSlot := primitives.Slot(0) - p := StateProvider{ + p := BeaconDbStater{ BeaconDB: db, ReplayerBuilder: ch, GenesisTimeFetcher: &chainMock.ChainService{Slot: ¤tSlot}, @@ -98,7 +98,7 @@ func TestGetState(t *testing.T) { replayer.SetMockStateForSlot(newBeaconState, params.BeaconConfig().SlotsPerEpoch*10) stateGen.StatesByRoot[stateRoot] = newBeaconState - p := StateProvider{ + p := BeaconDbStater{ ChainInfoFetcher: &chainMock.ChainService{ FinalizedCheckPoint: ðpb.Checkpoint{ Root: stateRoot[:], @@ -122,7 +122,7 @@ func TestGetState(t *testing.T) { replayer.SetMockStateForSlot(newBeaconState, params.BeaconConfig().SlotsPerEpoch*10) stateGen.StatesByRoot[stateRoot] = newBeaconState - p := StateProvider{ + p := BeaconDbStater{ ChainInfoFetcher: &chainMock.ChainService{ CurrentJustifiedCheckPoint: ðpb.Checkpoint{ Root: stateRoot[:], @@ -146,7 +146,7 @@ func TestGetState(t *testing.T) { stateGen := mockstategen.NewMockService() stateGen.StatesByRoot[bytesutil.ToBytes32(stateId)] = newBeaconState - p := StateProvider{ + p := BeaconDbStater{ ChainInfoFetcher: &chainMock.ChainService{State: newBeaconState}, StateGenService: stateGen, } @@ -159,7 +159,7 @@ func TestGetState(t *testing.T) { }) t.Run("hex_root_not_found", func(t *testing.T) { - p := StateProvider{ + p := BeaconDbStater{ ChainInfoFetcher: &chainMock.ChainService{State: newBeaconState}, } stateId, err := hexutil.Decode("0x" + strings.Repeat("f", 64)) @@ -169,7 +169,7 @@ func TestGetState(t *testing.T) { }) t.Run("slot", func(t *testing.T) { - p := StateProvider{ + p := BeaconDbStater{ GenesisTimeFetcher: &chainMock.ChainService{Slot: &headSlot}, ChainInfoFetcher: &chainMock.ChainService{ CanonicalRoots: map[[32]byte]bool{ @@ -188,7 +188,7 @@ func TestGetState(t *testing.T) { }) t.Run("invalid_state", func(t *testing.T) { - p := StateProvider{} + p := BeaconDbStater{} _, err := p.State(ctx, []byte("foo")) require.ErrorContains(t, "could not parse state ID", err) }) @@ -212,7 +212,7 @@ func TestGetStateRoot(t *testing.T) { b.Block.StateRoot = stateRoot[:] wsb, err := blocks.NewSignedBeaconBlock(b) require.NoError(t, err) - p := StateProvider{ + p := BeaconDbStater{ ChainInfoFetcher: &chainMock.ChainService{ State: newBeaconState, Block: wsb, @@ -241,7 +241,7 @@ func TestGetStateRoot(t *testing.T) { require.NoError(t, db.SaveGenesisBlockRoot(ctx, r)) require.NoError(t, db.SaveState(ctx, bs, r)) - p := StateProvider{ + p := BeaconDbStater{ BeaconDB: db, } @@ -275,7 +275,7 @@ func TestGetStateRoot(t *testing.T) { require.NoError(t, db.SaveState(ctx, st, root)) require.NoError(t, db.SaveFinalizedCheckpoint(ctx, cp)) - p := StateProvider{ + p := BeaconDbStater{ BeaconDB: db, } @@ -306,7 +306,7 @@ func TestGetStateRoot(t *testing.T) { require.NoError(t, db.SaveState(ctx, st, root)) require.NoError(t, db.SaveJustifiedCheckpoint(ctx, cp)) - p := StateProvider{ + p := BeaconDbStater{ BeaconDB: db, } @@ -319,7 +319,7 @@ func TestGetStateRoot(t *testing.T) { stateId, err := hexutil.Decode("0x" + strings.Repeat("0", 63) + "1") require.NoError(t, err) - p := StateProvider{ + p := BeaconDbStater{ ChainInfoFetcher: &chainMock.ChainService{State: newBeaconState}, } @@ -329,7 +329,7 @@ func TestGetStateRoot(t *testing.T) { }) t.Run("hex_root_not_found", func(t *testing.T) { - p := StateProvider{ + p := BeaconDbStater{ ChainInfoFetcher: &chainMock.ChainService{State: newBeaconState}, } stateId, err := hexutil.Decode("0x" + strings.Repeat("f", 64)) @@ -355,7 +355,7 @@ func TestGetStateRoot(t *testing.T) { require.NoError(t, db.SaveState(ctx, st, root)) slot := primitives.Slot(40) - p := StateProvider{ + p := BeaconDbStater{ GenesisTimeFetcher: &chainMock.ChainService{Slot: &slot}, BeaconDB: db, } @@ -366,7 +366,7 @@ func TestGetStateRoot(t *testing.T) { }) t.Run("slot_too_big", func(t *testing.T) { - p := StateProvider{ + p := BeaconDbStater{ GenesisTimeFetcher: &chainMock.ChainService{ Genesis: time.Now(), }, @@ -376,7 +376,7 @@ func TestGetStateRoot(t *testing.T) { }) t.Run("invalid_state", func(t *testing.T) { - p := StateProvider{} + p := BeaconDbStater{} _, err := p.StateRoot(ctx, []byte("foo")) require.ErrorContains(t, "could not parse state ID", err) }) @@ -389,7 +389,7 @@ func TestNewStateNotFoundError(t *testing.T) { func TestStateBySlot_FutureSlot(t *testing.T) { slot := primitives.Slot(100) - p := StateProvider{GenesisTimeFetcher: &chainMock.ChainService{Slot: &slot}} + p := BeaconDbStater{GenesisTimeFetcher: &chainMock.ChainService{Slot: &slot}} _, err := p.StateBySlot(context.Background(), 101) assert.ErrorContains(t, "requested slot is in the future", err) } @@ -403,7 +403,7 @@ func TestStateBySlot_AfterHeadSlot(t *testing.T) { mock := &chainMock.ChainService{State: headSt, Slot: ¤tSlot} mockReplayer := mockstategen.NewMockReplayerBuilder() mockReplayer.SetMockStateForSlot(slotSt, 101) - p := StateProvider{ChainInfoFetcher: mock, GenesisTimeFetcher: mock, ReplayerBuilder: mockReplayer} + p := BeaconDbStater{ChainInfoFetcher: mock, GenesisTimeFetcher: mock, ReplayerBuilder: mockReplayer} st, err := p.StateBySlot(context.Background(), 101) require.NoError(t, err) assert.Equal(t, primitives.Slot(101), st.Slot()) diff --git a/beacon-chain/rpc/service.go b/beacon-chain/rpc/service.go index 689dcf00c424..55e241832a16 100644 --- a/beacon-chain/rpc/service.go +++ b/beacon-chain/rpc/service.go @@ -8,6 +8,7 @@ import ( "net" "sync" + "github.com/gorilla/mux" middleware "github.com/grpc-ecosystem/go-grpc-middleware" recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery" grpcopentracing "github.com/grpc-ecosystem/go-grpc-middleware/tracing/opentracing" @@ -32,12 +33,13 @@ import ( "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/debug" "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/events" "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/node" + "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/rewards" "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/validator" + "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup" beaconv1alpha1 "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/prysm/v1alpha1/beacon" debugv1alpha1 "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/prysm/v1alpha1/debug" nodev1alpha1 "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/prysm/v1alpha1/node" validatorv1alpha1 "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/prysm/v1alpha1/validator" - "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/statefetcher" slasherservice "github.com/prysmaticlabs/prysm/v4/beacon-chain/slasher" "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen" chainSync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync" @@ -117,6 +119,7 @@ type Config struct { ProposerIdsCache *cache.ProposerPayloadIDsCache OptimisticModeFetcher blockchain.OptimisticModeFetcher BlockBuilder builder.BlockBuilder + Router *mux.Router } // NewService instantiates a new RPC service instance that will @@ -189,6 +192,25 @@ func (s *Service) Start() { } withCache := stategen.WithCache(stateCache) ch := stategen.NewCanonicalHistory(s.cfg.BeaconDB, s.cfg.ChainInfoFetcher, s.cfg.ChainInfoFetcher, withCache) + stater := &lookup.BeaconDbStater{ + BeaconDB: s.cfg.BeaconDB, + ChainInfoFetcher: s.cfg.ChainInfoFetcher, + GenesisTimeFetcher: s.cfg.GenesisTimeFetcher, + StateGenService: s.cfg.StateGen, + ReplayerBuilder: ch, + } + blocker := &lookup.BeaconDbBlocker{ + BeaconDB: s.cfg.BeaconDB, + ChainInfoFetcher: s.cfg.ChainInfoFetcher, + } + + rewardsServer := &rewards.Server{ + Blocker: blocker, + OptimisticModeFetcher: s.cfg.OptimisticModeFetcher, + FinalizationFetcher: s.cfg.FinalizationFetcher, + ReplayerBuilder: ch, + } + s.cfg.Router.HandleFunc("/eth/v1/beacon/rewards/blocks/{block_id}", rewardsServer.BlockRewards) validatorServer := &validatorv1alpha1.Server{ Ctx: s.ctx, @@ -226,21 +248,15 @@ func (s *Service) Start() { BLSChangesPool: s.cfg.BLSChangesPool, } validatorServerV1 := &validator.Server{ - HeadFetcher: s.cfg.HeadFetcher, - TimeFetcher: s.cfg.GenesisTimeFetcher, - SyncChecker: s.cfg.SyncService, - OptimisticModeFetcher: s.cfg.OptimisticModeFetcher, - AttestationsPool: s.cfg.AttestationsPool, - PeerManager: s.cfg.PeerManager, - Broadcaster: s.cfg.Broadcaster, - V1Alpha1Server: validatorServer, - StateFetcher: &statefetcher.StateProvider{ - BeaconDB: s.cfg.BeaconDB, - ChainInfoFetcher: s.cfg.ChainInfoFetcher, - GenesisTimeFetcher: s.cfg.GenesisTimeFetcher, - StateGenService: s.cfg.StateGen, - ReplayerBuilder: ch, - }, + HeadFetcher: s.cfg.HeadFetcher, + TimeFetcher: s.cfg.GenesisTimeFetcher, + SyncChecker: s.cfg.SyncService, + OptimisticModeFetcher: s.cfg.OptimisticModeFetcher, + AttestationsPool: s.cfg.AttestationsPool, + PeerManager: s.cfg.PeerManager, + Broadcaster: s.cfg.Broadcaster, + V1Alpha1Server: validatorServer, + Stater: stater, SyncCommitteePool: s.cfg.SyncCommitteeObjectPool, ProposerSlotIndexCache: s.cfg.ProposerIdsCache, ChainInfoFetcher: s.cfg.ChainInfoFetcher, @@ -298,24 +314,19 @@ func (s *Service) Start() { ReplayerBuilder: ch, } beaconChainServerV1 := &beacon.Server{ - CanonicalHistory: ch, - BeaconDB: s.cfg.BeaconDB, - AttestationsPool: s.cfg.AttestationsPool, - SlashingsPool: s.cfg.SlashingsPool, - ChainInfoFetcher: s.cfg.ChainInfoFetcher, - GenesisTimeFetcher: s.cfg.GenesisTimeFetcher, - BlockNotifier: s.cfg.BlockNotifier, - OperationNotifier: s.cfg.OperationNotifier, - Broadcaster: s.cfg.Broadcaster, - BlockReceiver: s.cfg.BlockReceiver, - StateGenService: s.cfg.StateGen, - StateFetcher: &statefetcher.StateProvider{ - BeaconDB: s.cfg.BeaconDB, - ChainInfoFetcher: s.cfg.ChainInfoFetcher, - GenesisTimeFetcher: s.cfg.GenesisTimeFetcher, - StateGenService: s.cfg.StateGen, - ReplayerBuilder: ch, - }, + CanonicalHistory: ch, + BeaconDB: s.cfg.BeaconDB, + AttestationsPool: s.cfg.AttestationsPool, + SlashingsPool: s.cfg.SlashingsPool, + ChainInfoFetcher: s.cfg.ChainInfoFetcher, + GenesisTimeFetcher: s.cfg.GenesisTimeFetcher, + BlockNotifier: s.cfg.BlockNotifier, + OperationNotifier: s.cfg.OperationNotifier, + Broadcaster: s.cfg.Broadcaster, + BlockReceiver: s.cfg.BlockReceiver, + StateGenService: s.cfg.StateGen, + Stater: stater, + Blocker: blocker, OptimisticModeFetcher: s.cfg.OptimisticModeFetcher, HeadFetcher: s.cfg.HeadFetcher, VoluntaryExitsPool: s.cfg.ExitPool, @@ -350,15 +361,9 @@ func (s *Service) Start() { ReplayerBuilder: ch, } debugServerV1 := &debug.Server{ - BeaconDB: s.cfg.BeaconDB, - HeadFetcher: s.cfg.HeadFetcher, - StateFetcher: &statefetcher.StateProvider{ - BeaconDB: s.cfg.BeaconDB, - ChainInfoFetcher: s.cfg.ChainInfoFetcher, - GenesisTimeFetcher: s.cfg.GenesisTimeFetcher, - StateGenService: s.cfg.StateGen, - ReplayerBuilder: ch, - }, + BeaconDB: s.cfg.BeaconDB, + HeadFetcher: s.cfg.HeadFetcher, + Stater: stater, OptimisticModeFetcher: s.cfg.OptimisticModeFetcher, ForkFetcher: s.cfg.ForkFetcher, ForkchoiceFetcher: s.cfg.ForkchoiceFetcher, diff --git a/beacon-chain/rpc/service_test.go b/beacon-chain/rpc/service_test.go index 39fa40207240..2d0d5344ae6d 100644 --- a/beacon-chain/rpc/service_test.go +++ b/beacon-chain/rpc/service_test.go @@ -7,6 +7,7 @@ import ( "testing" "time" + "github.com/gorilla/mux" mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing" mockExecution "github.com/prysmaticlabs/prysm/v4/beacon-chain/execution/testing" mockSync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync/initial-sync/testing" @@ -35,6 +36,7 @@ func TestLifecycle_OK(t *testing.T) { GenesisTimeFetcher: chainService, ExecutionChainService: &mockExecution.Chain{}, StateNotifier: chainService.StateNotifier(), + Router: mux.NewRouter(), }) rpcService.Start() @@ -75,6 +77,7 @@ func TestRPC_InsecureEndpoint(t *testing.T) { HeadFetcher: chainService, ExecutionChainService: &mockExecution.Chain{}, StateNotifier: chainService.StateNotifier(), + Router: mux.NewRouter(), }) rpcService.Start() diff --git a/beacon-chain/rpc/testutil/BUILD.bazel b/beacon-chain/rpc/testutil/BUILD.bazel index b21ed3b928f1..27ca73821e29 100644 --- a/beacon-chain/rpc/testutil/BUILD.bazel +++ b/beacon-chain/rpc/testutil/BUILD.bazel @@ -4,15 +4,24 @@ go_library( name = "go_default_library", testonly = True, srcs = [ + "db.go", + "mock_blocker.go", "mock_exec_chain_info_fetcher.go", "mock_genesis_timefetcher.go", - "mock_state_fetcher.go", + "mock_stater.go", ], importpath = "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/testutil", visibility = ["//beacon-chain:__subpackages__"], deps = [ + "//beacon-chain/db:go_default_library", "//beacon-chain/state:go_default_library", "//config/params:go_default_library", + "//consensus-types/blocks:go_default_library", + "//consensus-types/interfaces:go_default_library", "//consensus-types/primitives:go_default_library", + "//encoding/bytesutil:go_default_library", + "//proto/prysm/v1alpha1:go_default_library", + "//testing/require:go_default_library", + "//testing/util:go_default_library", ], ) diff --git a/beacon-chain/rpc/testutil/db.go b/beacon-chain/rpc/testutil/db.go new file mode 100644 index 000000000000..65905770d719 --- /dev/null +++ b/beacon-chain/rpc/testutil/db.go @@ -0,0 +1,51 @@ +package testutil + +import ( + "context" + "testing" + + "github.com/prysmaticlabs/prysm/v4/beacon-chain/db" + "github.com/prysmaticlabs/prysm/v4/consensus-types/blocks" + "github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces" + "github.com/prysmaticlabs/prysm/v4/consensus-types/primitives" + "github.com/prysmaticlabs/prysm/v4/encoding/bytesutil" + ethpbalpha "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/prysm/v4/testing/require" + "github.com/prysmaticlabs/prysm/v4/testing/util" +) + +func FillDBWithBlocks(ctx context.Context, t *testing.T, beaconDB db.Database) (*ethpbalpha.SignedBeaconBlock, []*ethpbalpha.BeaconBlockContainer) { + parentRoot := [32]byte{1, 2, 3} + genBlk := util.NewBeaconBlock() + genBlk.Block.ParentRoot = parentRoot[:] + root, err := genBlk.Block.HashTreeRoot() + require.NoError(t, err) + util.SaveBlock(t, ctx, beaconDB, genBlk) + require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, root)) + + count := primitives.Slot(100) + blks := make([]interfaces.ReadOnlySignedBeaconBlock, count) + blkContainers := make([]*ethpbalpha.BeaconBlockContainer, count) + for i := primitives.Slot(0); i < count; i++ { + b := util.NewBeaconBlock() + b.Block.Slot = i + b.Block.ParentRoot = bytesutil.PadTo([]byte{uint8(i)}, 32) + root, err := b.Block.HashTreeRoot() + require.NoError(t, err) + blks[i], err = blocks.NewSignedBeaconBlock(b) + require.NoError(t, err) + blkContainers[i] = ðpbalpha.BeaconBlockContainer{ + Block: ðpbalpha.BeaconBlockContainer_Phase0Block{Phase0Block: b}, + BlockRoot: root[:], + } + } + require.NoError(t, beaconDB.SaveBlocks(ctx, blks)) + headRoot := bytesutil.ToBytes32(blkContainers[len(blks)-1].BlockRoot) + summary := ðpbalpha.StateSummary{ + Root: headRoot[:], + Slot: blkContainers[len(blks)-1].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block.Block.Slot, + } + require.NoError(t, beaconDB.SaveStateSummary(ctx, summary)) + require.NoError(t, beaconDB.SaveHeadBlockRoot(ctx, headRoot)) + return genBlk, blkContainers +} diff --git a/beacon-chain/rpc/testutil/mock_blocker.go b/beacon-chain/rpc/testutil/mock_blocker.go new file mode 100644 index 000000000000..dac5a8851071 --- /dev/null +++ b/beacon-chain/rpc/testutil/mock_blocker.go @@ -0,0 +1,28 @@ +package testutil + +import ( + "context" + "strconv" + + "github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces" + "github.com/prysmaticlabs/prysm/v4/consensus-types/primitives" +) + +// MockBlocker is a fake implementation of lookup.Blocker. +type MockBlocker struct { + BlockToReturn interfaces.ReadOnlySignedBeaconBlock + ErrorToReturn error + SlotBlockMap map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock +} + +// Block -- +func (m *MockBlocker) Block(_ context.Context, b []byte) (interfaces.ReadOnlySignedBeaconBlock, error) { + if m.ErrorToReturn != nil { + return nil, m.ErrorToReturn + } + slotNumber, parseErr := strconv.ParseUint(string(b), 10, 64) + if parseErr != nil { + return m.BlockToReturn, nil + } + return m.SlotBlockMap[primitives.Slot(slotNumber)], nil +} diff --git a/beacon-chain/rpc/testutil/mock_state_fetcher.go b/beacon-chain/rpc/testutil/mock_stater.go similarity index 53% rename from beacon-chain/rpc/testutil/mock_state_fetcher.go rename to beacon-chain/rpc/testutil/mock_stater.go index e0e59225cf7a..4e7a5f728c8d 100644 --- a/beacon-chain/rpc/testutil/mock_state_fetcher.go +++ b/beacon-chain/rpc/testutil/mock_stater.go @@ -7,23 +7,24 @@ import ( "github.com/prysmaticlabs/prysm/v4/consensus-types/primitives" ) -// MockFetcher is a fake implementation of statefetcher.Fetcher. -type MockFetcher struct { +// MockStater is a fake implementation of lookup.Stater. +type MockStater struct { BeaconState state.BeaconState BeaconStateRoot []byte StatesBySlot map[primitives.Slot]state.BeaconState } // State -- -func (m *MockFetcher) State(context.Context, []byte) (state.BeaconState, error) { +func (m *MockStater) State(context.Context, []byte) (state.BeaconState, error) { return m.BeaconState, nil } // StateRoot -- -func (m *MockFetcher) StateRoot(context.Context, []byte) ([]byte, error) { +func (m *MockStater) StateRoot(context.Context, []byte) ([]byte, error) { return m.BeaconStateRoot, nil } -func (m *MockFetcher) StateBySlot(_ context.Context, s primitives.Slot) (state.BeaconState, error) { +// StateBySlot -- +func (m *MockStater) StateBySlot(_ context.Context, s primitives.Slot) (state.BeaconState, error) { return m.StatesBySlot[s], nil } diff --git a/beacon-chain/server/main.go b/beacon-chain/server/main.go index ff3c951d0a58..cf2b5fec8fb8 100644 --- a/beacon-chain/server/main.go +++ b/beacon-chain/server/main.go @@ -45,6 +45,7 @@ func main() { log.SetLevel(logrus.DebugLevel) } + r := mux.NewRouter() gatewayConfig := beaconGateway.DefaultConfig(*enableDebugRPCEndpoints, *httpModules) muxs := make([]*gateway.PbMux, 0) if gatewayConfig.V1AlphaPbMux != nil { @@ -54,6 +55,7 @@ func main() { muxs = append(muxs, gatewayConfig.EthPbMux) } opts := []gateway.Option{ + gateway.WithRouter(r), gateway.WithPbHandlers(muxs), gateway.WithMuxHandler(gatewayConfig.Handler), gateway.WithRemoteAddr(*beaconRPC), @@ -71,10 +73,8 @@ func main() { log.Fatal(err) } - r := mux.NewRouter() r.HandleFunc("/swagger/", gateway.SwaggerServer()) r.HandleFunc("/healthz", healthzServer(gw)) - gw.SetRouter(r) gw.Start() diff --git a/network/BUILD.bazel b/network/BUILD.bazel index 99f460c42653..1412b2d2a7d1 100644 --- a/network/BUILD.bazel +++ b/network/BUILD.bazel @@ -6,6 +6,7 @@ go_library( "auth.go", "endpoint.go", "external_ip.go", + "writer.go", ], importpath = "github.com/prysmaticlabs/prysm/v4/network", visibility = ["//visibility:public"], @@ -13,6 +14,7 @@ go_library( "//network/authorization:go_default_library", "@com_github_golang_jwt_jwt_v4//:go_default_library", "@com_github_pkg_errors//:go_default_library", + "@com_github_sirupsen_logrus//:go_default_library", ], ) diff --git a/network/writer.go b/network/writer.go new file mode 100644 index 000000000000..f7b886a16223 --- /dev/null +++ b/network/writer.go @@ -0,0 +1,41 @@ +package network + +import ( + "bytes" + "encoding/json" + "io" + "net/http" + "strconv" + + log "github.com/sirupsen/logrus" +) + +// DefaultErrorJson is a JSON representation of a simple error value, containing only a message and an error code. +type DefaultErrorJson struct { + Message string `json:"message"` + Code int `json:"code"` +} + +// WriteJson writes the response message in JSON format. +func WriteJson(w http.ResponseWriter, v any) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + if err := json.NewEncoder(w).Encode(v); err != nil { + log.WithError(err).Error("Could not write response message") + } +} + +// WriteError writes the error by manipulating headers and the body of the final response. +func WriteError(w http.ResponseWriter, errJson *DefaultErrorJson) { + j, err := json.Marshal(errJson) + if err != nil { + log.WithError(err).Error("Could not marshal error message") + return + } + w.Header().Set("Content-Length", strconv.Itoa(len(j))) + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(errJson.Code) + if _, err := io.Copy(w, io.NopCloser(bytes.NewReader(j))); err != nil { + log.WithError(err).Error("Could not write error message") + } +} diff --git a/validator/node/BUILD.bazel b/validator/node/BUILD.bazel index 60e2855e2c3a..06c7bf5c723e 100644 --- a/validator/node/BUILD.bazel +++ b/validator/node/BUILD.bazel @@ -69,6 +69,7 @@ go_library( "//validator/web:go_default_library", "@com_github_ethereum_go_ethereum//common:go_default_library", "@com_github_ethereum_go_ethereum//common/hexutil:go_default_library", + "@com_github_gorilla_mux//:go_default_library", "@com_github_grpc_ecosystem_grpc_gateway_v2//runtime:go_default_library", "@com_github_pkg_errors//:go_default_library", "@com_github_prysmaticlabs_fastssz//:go_default_library", diff --git a/validator/node/node.go b/validator/node/node.go index f58edf38a43f..7d3713752929 100644 --- a/validator/node/node.go +++ b/validator/node/node.go @@ -22,6 +22,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/gorilla/mux" gwruntime "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "github.com/pkg/errors" fastssz "github.com/prysmaticlabs/fastssz" @@ -764,6 +765,7 @@ func (c *ValidatorClient) registerRPCGatewayService(cliCtx *cli.Context) error { Mux: gwmux, } opts := []gateway.Option{ + gateway.WithRouter(mux.NewRouter()), gateway.WithRemoteAddr(rpcAddr), gateway.WithGatewayAddr(gatewayAddress), gateway.WithMaxCallRecvMsgSize(maxCallSize),