package validator

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

	"github.com/OffchainLabs/prysm/v6/api"
	"github.com/OffchainLabs/prysm/v6/api/server/structs"
	blockchainTesting "github.com/OffchainLabs/prysm/v6/beacon-chain/blockchain/testing"
	rewardtesting "github.com/OffchainLabs/prysm/v6/beacon-chain/rpc/eth/rewards/testing"
	rpctesting "github.com/OffchainLabs/prysm/v6/beacon-chain/rpc/eth/shared/testing"
	mockSync "github.com/OffchainLabs/prysm/v6/beacon-chain/sync/initial-sync/testing"
	"github.com/OffchainLabs/prysm/v6/network/httputil"
	eth "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
	"github.com/OffchainLabs/prysm/v6/testing/assert"
	mock2 "github.com/OffchainLabs/prysm/v6/testing/mock"
	"github.com/OffchainLabs/prysm/v6/testing/require"
	"github.com/ethereum/go-ethereum/common/hexutil"
	"go.uber.org/mock/gomock"
)

func TestProduceBlockV3(t *testing.T) {
	ctrl := gomock.NewController(t)
	randao := "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"
	graffiti := "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
	bRandao, err := hexutil.Decode(randao)
	require.NoError(t, err)
	bGraffiti, err := hexutil.Decode(graffiti)
	require.NoError(t, err)
	chainService := &blockchainTesting.ChainService{}
	syncChecker := &mockSync.Sync{IsSyncing: false}
	rewardFetcher := &rewardtesting.MockBlockRewardFetcher{Rewards: &structs.BlockRewards{Total: "10"}}

	t.Run("Phase 0", func(t *testing.T) {
		var block *structs.SignedBeaconBlock
		err := json.Unmarshal([]byte(rpctesting.Phase0Block), &block)
		require.NoError(t, err)
		jsonBytes, err := json.Marshal(block.Message)
		require.NoError(t, err)
		v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
		v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
			Slot:         1,
			RandaoReveal: bRandao,
			Graffiti:     bGraffiti,
			SkipMevBoost: false,
		}).Return(
			func() (*eth.GenericBeaconBlock, error) {
				return block.Message.ToGeneric()
			}())
		server := &Server{
			V1Alpha1Server: v1alpha1Server,
			SyncChecker:    syncChecker,
		}
		request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
		writer := httptest.NewRecorder()
		writer.Body = &bytes.Buffer{}
		server.ProduceBlockV3(writer, request)
		assert.Equal(t, http.StatusOK, writer.Code)
		want := fmt.Sprintf(`{"version":"phase0","execution_payload_blinded":false,"execution_payload_value":"","consensus_block_value":"","data":%s}`, string(jsonBytes))
		body := strings.ReplaceAll(writer.Body.String(), "\n", "")
		require.Equal(t, want, body)
		require.Equal(t, "false", writer.Header().Get(api.ExecutionPayloadBlindedHeader))
		require.Equal(t, "", writer.Header().Get(api.ExecutionPayloadValueHeader))
		require.Equal(t, "phase0", writer.Header().Get(api.VersionHeader))
		require.Equal(t, "", writer.Header().Get(api.ConsensusBlockValueHeader))
	})
	t.Run("Altair", func(t *testing.T) {
		var block *structs.SignedBeaconBlockAltair
		err := json.Unmarshal([]byte(rpctesting.AltairBlock), &block)

		require.NoError(t, err)
		jsonBytes, err := json.Marshal(block.Message)
		require.NoError(t, err)
		v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
		v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
			Slot:         1,
			RandaoReveal: bRandao,
			Graffiti:     bGraffiti,
			SkipMevBoost: false,
		}).Return(
			func() (*eth.GenericBeaconBlock, error) {

				return block.Message.ToGeneric()
			}())
		server := &Server{
			V1Alpha1Server:     v1alpha1Server,
			SyncChecker:        syncChecker,
			BlockRewardFetcher: rewardFetcher,
		}
		request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
		writer := httptest.NewRecorder()
		writer.Body = &bytes.Buffer{}
		server.ProduceBlockV3(writer, request)
		assert.Equal(t, http.StatusOK, writer.Code)
		want := fmt.Sprintf(`{"version":"altair","execution_payload_blinded":false,"execution_payload_value":"","consensus_block_value":"10000000000","data":%s}`, string(jsonBytes))
		body := strings.ReplaceAll(writer.Body.String(), "\n", "")
		require.Equal(t, want, body)
		require.Equal(t, "false", writer.Header().Get(api.ExecutionPayloadBlindedHeader))
		require.Equal(t, "", writer.Header().Get(api.ExecutionPayloadValueHeader))
		require.Equal(t, "altair", writer.Header().Get(api.VersionHeader))
		require.Equal(t, "10000000000", writer.Header().Get(api.ConsensusBlockValueHeader))
	})
	t.Run("Bellatrix", func(t *testing.T) {
		var block *structs.SignedBeaconBlockBellatrix
		err := json.Unmarshal([]byte(rpctesting.BellatrixBlock), &block)
		require.NoError(t, err)
		jsonBytes, err := json.Marshal(block.Message)
		require.NoError(t, err)
		v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
		v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
			Slot:         1,
			RandaoReveal: bRandao,
			Graffiti:     bGraffiti,
			SkipMevBoost: false,
		}).Return(
			func() (*eth.GenericBeaconBlock, error) {
				b, err := block.Message.ToGeneric()
				require.NoError(t, err)
				b.PayloadValue = "2000"
				return b, nil
			}())
		server := &Server{
			V1Alpha1Server:        v1alpha1Server,
			SyncChecker:           syncChecker,
			OptimisticModeFetcher: chainService,
			BlockRewardFetcher:    rewardFetcher,
		}
		request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
		writer := httptest.NewRecorder()
		writer.Body = &bytes.Buffer{}
		server.ProduceBlockV3(writer, request)
		assert.Equal(t, http.StatusOK, writer.Code)
		want := fmt.Sprintf(`{"version":"bellatrix","execution_payload_blinded":false,"execution_payload_value":"2000","consensus_block_value":"10000000000","data":%s}`, string(jsonBytes))
		body := strings.ReplaceAll(writer.Body.String(), "\n", "")
		require.Equal(t, want, body)
		require.Equal(t, "false", writer.Header().Get(api.ExecutionPayloadBlindedHeader))
		require.Equal(t, "2000", writer.Header().Get(api.ExecutionPayloadValueHeader))
		require.Equal(t, "bellatrix", writer.Header().Get(api.VersionHeader))
		require.Equal(t, "10000000000", writer.Header().Get(api.ConsensusBlockValueHeader))
	})
	t.Run("BlindedBellatrix", func(t *testing.T) {
		var block *structs.SignedBlindedBeaconBlockBellatrix
		err := json.Unmarshal([]byte(rpctesting.BlindedBellatrixBlock), &block)
		require.NoError(t, err)
		jsonBytes, err := json.Marshal(block.Message)
		require.NoError(t, err)
		v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
		v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
			Slot:         1,
			RandaoReveal: bRandao,
			Graffiti:     bGraffiti,
			SkipMevBoost: false,
		}).Return(
			func() (*eth.GenericBeaconBlock, error) {
				b, err := block.Message.ToGeneric()
				require.NoError(t, err)
				b.PayloadValue = "2000"
				return b, nil
			}())
		server := &Server{
			V1Alpha1Server:        v1alpha1Server,
			SyncChecker:           syncChecker,
			OptimisticModeFetcher: chainService,
			BlockRewardFetcher:    rewardFetcher,
		}
		request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
		writer := httptest.NewRecorder()
		writer.Body = &bytes.Buffer{}
		server.ProduceBlockV3(writer, request)
		assert.Equal(t, http.StatusOK, writer.Code)
		want := fmt.Sprintf(`{"version":"bellatrix","execution_payload_blinded":true,"execution_payload_value":"2000","consensus_block_value":"10000000000","data":%s}`, string(jsonBytes))
		body := strings.ReplaceAll(writer.Body.String(), "\n", "")
		require.Equal(t, want, body)
		require.Equal(t, "true", writer.Header().Get(api.ExecutionPayloadBlindedHeader))
		require.Equal(t, "2000", writer.Header().Get(api.ExecutionPayloadValueHeader))
		require.Equal(t, "bellatrix", writer.Header().Get(api.VersionHeader))
		require.Equal(t, "10000000000", writer.Header().Get(api.ConsensusBlockValueHeader))
	})
	t.Run("Capella", func(t *testing.T) {
		var block *structs.SignedBeaconBlockCapella
		err := json.Unmarshal([]byte(rpctesting.CapellaBlock), &block)
		require.NoError(t, err)
		jsonBytes, err := json.Marshal(block.Message)
		require.NoError(t, err)
		v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
		v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
			Slot:         1,
			RandaoReveal: bRandao,
			Graffiti:     bGraffiti,
			SkipMevBoost: false,
		}).Return(
			func() (*eth.GenericBeaconBlock, error) {
				b, err := block.Message.ToGeneric()
				require.NoError(t, err)
				b.PayloadValue = "2000"
				return b, nil
			}())
		server := &Server{
			V1Alpha1Server:        v1alpha1Server,
			SyncChecker:           syncChecker,
			OptimisticModeFetcher: chainService,
			BlockRewardFetcher:    rewardFetcher,
		}
		request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
		writer := httptest.NewRecorder()
		writer.Body = &bytes.Buffer{}
		server.ProduceBlockV3(writer, request)
		assert.Equal(t, http.StatusOK, writer.Code)
		want := fmt.Sprintf(`{"version":"capella","execution_payload_blinded":false,"execution_payload_value":"2000","consensus_block_value":"10000000000","data":%s}`, string(jsonBytes))
		body := strings.ReplaceAll(writer.Body.String(), "\n", "")
		require.Equal(t, want, body)
		require.Equal(t, "false", writer.Header().Get(api.ExecutionPayloadBlindedHeader))
		require.Equal(t, "2000", writer.Header().Get(api.ExecutionPayloadValueHeader))
		require.Equal(t, "capella", writer.Header().Get(api.VersionHeader))
		require.Equal(t, "10000000000", writer.Header().Get(api.ConsensusBlockValueHeader))
	})
	t.Run("Blinded Capella", func(t *testing.T) {
		var block *structs.SignedBlindedBeaconBlockCapella
		err := json.Unmarshal([]byte(rpctesting.BlindedCapellaBlock), &block)
		require.NoError(t, err)
		jsonBytes, err := json.Marshal(block.Message)
		require.NoError(t, err)
		v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
		v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
			Slot:         1,
			RandaoReveal: bRandao,
			Graffiti:     bGraffiti,
			SkipMevBoost: false,
		}).Return(
			func() (*eth.GenericBeaconBlock, error) {
				g, err := block.Message.ToGeneric()
				require.NoError(t, err)
				g.PayloadValue = "2000"
				return g, err
			}())
		server := &Server{
			V1Alpha1Server:        v1alpha1Server,
			SyncChecker:           syncChecker,
			OptimisticModeFetcher: chainService,
			BlockRewardFetcher:    rewardFetcher,
		}
		request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
		writer := httptest.NewRecorder()
		writer.Body = &bytes.Buffer{}
		server.ProduceBlockV3(writer, request)
		assert.Equal(t, http.StatusOK, writer.Code)
		want := fmt.Sprintf(`{"version":"capella","execution_payload_blinded":true,"execution_payload_value":"2000","consensus_block_value":"10000000000","data":%s}`, string(jsonBytes))
		body := strings.ReplaceAll(writer.Body.String(), "\n", "")
		require.Equal(t, want, body)
		require.Equal(t, "true", writer.Header().Get(api.ExecutionPayloadBlindedHeader))
		require.Equal(t, "2000", writer.Header().Get(api.ExecutionPayloadValueHeader))
		require.Equal(t, "capella", writer.Header().Get(api.VersionHeader))
		require.Equal(t, "10000000000", writer.Header().Get(api.ConsensusBlockValueHeader))
	})
	t.Run("Deneb", func(t *testing.T) {
		var block *structs.SignedBeaconBlockContentsDeneb
		err := json.Unmarshal([]byte(rpctesting.DenebBlockContents), &block)
		require.NoError(t, err)
		jsonBytes, err := json.Marshal(block.ToUnsigned())
		require.NoError(t, err)
		v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
		v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
			Slot:         1,
			RandaoReveal: bRandao,
			Graffiti:     bGraffiti,
			SkipMevBoost: false,
		}).Return(
			func() (*eth.GenericBeaconBlock, error) {
				b, err := block.ToUnsigned().ToGeneric()
				require.NoError(t, err)
				b.PayloadValue = "2000"
				return b, nil
			}())
		server := &Server{
			V1Alpha1Server:        v1alpha1Server,
			SyncChecker:           syncChecker,
			OptimisticModeFetcher: chainService,
			BlockRewardFetcher:    rewardFetcher,
		}
		request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
		writer := httptest.NewRecorder()
		writer.Body = &bytes.Buffer{}
		server.ProduceBlockV3(writer, request)
		assert.Equal(t, http.StatusOK, writer.Code)
		want := fmt.Sprintf(`{"version":"deneb","execution_payload_blinded":false,"execution_payload_value":"2000","consensus_block_value":"10000000000","data":%s}`, string(jsonBytes))
		body := strings.ReplaceAll(writer.Body.String(), "\n", "")
		require.Equal(t, want, body)
		require.Equal(t, "false", writer.Header().Get(api.ExecutionPayloadBlindedHeader))
		require.Equal(t, "2000", writer.Header().Get(api.ExecutionPayloadValueHeader))
		require.Equal(t, "deneb", writer.Header().Get(api.VersionHeader))
		require.Equal(t, "10000000000", writer.Header().Get(api.ConsensusBlockValueHeader))
	})
	t.Run("Blinded Deneb", func(t *testing.T) {
		var block *structs.SignedBlindedBeaconBlockDeneb
		err := json.Unmarshal([]byte(rpctesting.BlindedDenebBlock), &block)
		require.NoError(t, err)
		jsonBytes, err := json.Marshal(block.Message)
		require.NoError(t, err)
		v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
		v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
			Slot:         1,
			RandaoReveal: bRandao,
			Graffiti:     bGraffiti,
			SkipMevBoost: false,
		}).Return(
			func() (*eth.GenericBeaconBlock, error) {
				b, err := block.Message.ToGeneric()
				require.NoError(t, err)
				b.PayloadValue = "2000"
				return b, nil
			}())
		server := &Server{
			V1Alpha1Server:        v1alpha1Server,
			SyncChecker:           syncChecker,
			OptimisticModeFetcher: chainService,
			BlockRewardFetcher:    rewardFetcher,
		}
		request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
		writer := httptest.NewRecorder()
		writer.Body = &bytes.Buffer{}
		server.ProduceBlockV3(writer, request)
		assert.Equal(t, http.StatusOK, writer.Code)
		want := fmt.Sprintf(`{"version":"deneb","execution_payload_blinded":true,"execution_payload_value":"2000","consensus_block_value":"10000000000","data":%s}`, string(jsonBytes))
		body := strings.ReplaceAll(writer.Body.String(), "\n", "")
		require.Equal(t, want, body)
		require.Equal(t, "true", writer.Header().Get(api.ExecutionPayloadBlindedHeader))
		require.Equal(t, "2000", writer.Header().Get(api.ExecutionPayloadValueHeader))
		require.Equal(t, "deneb", writer.Header().Get(api.VersionHeader))
		require.Equal(t, "10000000000", writer.Header().Get(api.ConsensusBlockValueHeader))
	})
	t.Run("Electra", func(t *testing.T) {
		var block *structs.SignedBeaconBlockContentsElectra
		err := json.Unmarshal([]byte(rpctesting.ElectraBlockContents), &block)
		require.NoError(t, err)
		jsonBytes, err := json.Marshal(block.ToUnsigned())
		require.NoError(t, err)
		v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
		v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
			Slot:         1,
			RandaoReveal: bRandao,
			Graffiti:     bGraffiti,
			SkipMevBoost: false,
		}).Return(
			func() (*eth.GenericBeaconBlock, error) {
				b, err := block.ToUnsigned().ToGeneric()
				require.NoError(t, err)
				b.PayloadValue = "2000"
				return b, nil
			}())
		server := &Server{
			V1Alpha1Server:        v1alpha1Server,
			SyncChecker:           syncChecker,
			OptimisticModeFetcher: chainService,
			BlockRewardFetcher:    rewardFetcher,
		}
		request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
		writer := httptest.NewRecorder()
		writer.Body = &bytes.Buffer{}
		server.ProduceBlockV3(writer, request)
		assert.Equal(t, http.StatusOK, writer.Code)
		want := fmt.Sprintf(`{"version":"electra","execution_payload_blinded":false,"execution_payload_value":"2000","consensus_block_value":"10000000000","data":%s}`, string(jsonBytes))
		body := strings.ReplaceAll(writer.Body.String(), "\n", "")
		require.Equal(t, want, body)
		require.Equal(t, "false", writer.Header().Get(api.ExecutionPayloadBlindedHeader))
		require.Equal(t, "2000", writer.Header().Get(api.ExecutionPayloadValueHeader))
		require.Equal(t, "electra", writer.Header().Get(api.VersionHeader))
		require.Equal(t, "10000000000", writer.Header().Get(api.ConsensusBlockValueHeader))
	})
	t.Run("Blinded Electra", func(t *testing.T) {
		var block *structs.SignedBlindedBeaconBlockElectra
		err := json.Unmarshal([]byte(rpctesting.BlindedElectraBlock), &block)
		require.NoError(t, err)
		jsonBytes, err := json.Marshal(block.Message)
		require.NoError(t, err)
		v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
		v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
			Slot:         1,
			RandaoReveal: bRandao,
			Graffiti:     bGraffiti,
			SkipMevBoost: false,
		}).Return(
			func() (*eth.GenericBeaconBlock, error) {
				b, err := block.Message.ToGeneric()
				require.NoError(t, err)
				b.PayloadValue = "2000"
				return b, nil
			}())
		server := &Server{
			V1Alpha1Server:        v1alpha1Server,
			SyncChecker:           syncChecker,
			OptimisticModeFetcher: chainService,
			BlockRewardFetcher:    rewardFetcher,
		}
		request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
		writer := httptest.NewRecorder()
		writer.Body = &bytes.Buffer{}
		server.ProduceBlockV3(writer, request)
		assert.Equal(t, http.StatusOK, writer.Code)
		want := fmt.Sprintf(`{"version":"electra","execution_payload_blinded":true,"execution_payload_value":"2000","consensus_block_value":"10000000000","data":%s}`, string(jsonBytes))
		body := strings.ReplaceAll(writer.Body.String(), "\n", "")
		require.Equal(t, want, body)
		require.Equal(t, "true", writer.Header().Get(api.ExecutionPayloadBlindedHeader))
		require.Equal(t, "2000", writer.Header().Get(api.ExecutionPayloadValueHeader))
		require.Equal(t, "electra", writer.Header().Get(api.VersionHeader))
		require.Equal(t, "10000000000", writer.Header().Get(api.ConsensusBlockValueHeader))
	})
	t.Run("Fulu", func(t *testing.T) {
		var block *structs.SignedBeaconBlockContentsFulu
		err := json.Unmarshal([]byte(rpctesting.FuluBlockContents), &block)
		require.NoError(t, err)
		jsonBytes, err := json.Marshal(block.ToUnsigned())
		require.NoError(t, err)
		v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
		v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
			Slot:         1,
			RandaoReveal: bRandao,
			Graffiti:     bGraffiti,
			SkipMevBoost: false,
		}).Return(
			func() (*eth.GenericBeaconBlock, error) {
				b, err := block.ToUnsigned().ToGeneric()
				require.NoError(t, err)
				b.PayloadValue = "2000"
				return b, nil
			}())
		server := &Server{
			V1Alpha1Server:        v1alpha1Server,
			SyncChecker:           syncChecker,
			OptimisticModeFetcher: chainService,
			BlockRewardFetcher:    rewardFetcher,
		}
		request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
		writer := httptest.NewRecorder()
		writer.Body = &bytes.Buffer{}
		server.ProduceBlockV3(writer, request)
		assert.Equal(t, http.StatusOK, writer.Code)
		want := fmt.Sprintf(`{"version":"fulu","execution_payload_blinded":false,"execution_payload_value":"2000","consensus_block_value":"10000000000","data":%s}`, string(jsonBytes))
		body := strings.ReplaceAll(writer.Body.String(), "\n", "")
		require.Equal(t, want, body)
		require.Equal(t, "false", writer.Header().Get(api.ExecutionPayloadBlindedHeader))
		require.Equal(t, "2000", writer.Header().Get(api.ExecutionPayloadValueHeader))
		require.Equal(t, "fulu", writer.Header().Get(api.VersionHeader))
		require.Equal(t, "10000000000", writer.Header().Get(api.ConsensusBlockValueHeader))
	})
	t.Run("Blinded Fulu", func(t *testing.T) {
		var block *structs.SignedBlindedBeaconBlockFulu
		err := json.Unmarshal([]byte(rpctesting.BlindedFuluBlock), &block)
		require.NoError(t, err)
		jsonBytes, err := json.Marshal(block.Message)
		require.NoError(t, err)
		v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
		v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
			Slot:         1,
			RandaoReveal: bRandao,
			Graffiti:     bGraffiti,
			SkipMevBoost: false,
		}).Return(
			func() (*eth.GenericBeaconBlock, error) {
				b, err := block.Message.ToGeneric()
				require.NoError(t, err)
				b.PayloadValue = "2000"
				return b, nil
			}())
		server := &Server{
			V1Alpha1Server:        v1alpha1Server,
			SyncChecker:           syncChecker,
			OptimisticModeFetcher: chainService,
			BlockRewardFetcher:    rewardFetcher,
		}
		request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
		writer := httptest.NewRecorder()
		writer.Body = &bytes.Buffer{}
		server.ProduceBlockV3(writer, request)
		assert.Equal(t, http.StatusOK, writer.Code)
		want := fmt.Sprintf(`{"version":"fulu","execution_payload_blinded":true,"execution_payload_value":"2000","consensus_block_value":"10000000000","data":%s}`, string(jsonBytes))
		body := strings.ReplaceAll(writer.Body.String(), "\n", "")
		require.Equal(t, want, body)
		require.Equal(t, "true", writer.Header().Get(api.ExecutionPayloadBlindedHeader))
		require.Equal(t, "2000", writer.Header().Get(api.ExecutionPayloadValueHeader))
		require.Equal(t, "fulu", writer.Header().Get(api.VersionHeader))
		require.Equal(t, "10000000000", writer.Header().Get(api.ConsensusBlockValueHeader))
	})
	t.Run("invalid query parameter slot empty", func(t *testing.T) {
		v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
		server := &Server{
			V1Alpha1Server: v1alpha1Server,
			SyncChecker:    &mockSync.Sync{IsSyncing: false},
		}
		request := httptest.NewRequest(http.MethodGet, "http://foo.example/eth/v3/validator/blocks/", nil)
		writer := httptest.NewRecorder()
		writer.Body = &bytes.Buffer{}
		server.ProduceBlockV3(writer, request)
		assert.Equal(t, http.StatusBadRequest, writer.Code)
		assert.Equal(t, true, strings.Contains(writer.Body.String(), "slot is required"))
	})
	t.Run("invalid query parameter slot invalid", func(t *testing.T) {
		v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
		server := &Server{
			V1Alpha1Server: v1alpha1Server,
			SyncChecker:    syncChecker,
		}
		request := httptest.NewRequest(http.MethodGet, "http://foo.example/eth/v3/validator/blocks/asdfsad", nil)
		writer := httptest.NewRecorder()
		writer.Body = &bytes.Buffer{}
		server.ProduceBlockV3(writer, request)
		assert.Equal(t, http.StatusBadRequest, writer.Code)
		assert.Equal(t, true, strings.Contains(writer.Body.String(), "slot is invalid"))
	})
	t.Run("invalid query parameter randao_reveal invalid", func(t *testing.T) {
		v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
		server := &Server{
			V1Alpha1Server: v1alpha1Server,
			SyncChecker:    syncChecker,
		}
		request := httptest.NewRequest(http.MethodGet, "http://foo.example/eth/v3/validator/blocks/1?randao_reveal=0x213123", nil)
		writer := httptest.NewRecorder()
		writer.Body = &bytes.Buffer{}
		server.ProduceBlockV3(writer, request)
		assert.Equal(t, http.StatusBadRequest, writer.Code)
	})
	t.Run("syncing", func(t *testing.T) {
		server := &Server{
			SyncChecker:           &mockSync.Sync{IsSyncing: true},
			HeadFetcher:           chainService,
			TimeFetcher:           chainService,
			OptimisticModeFetcher: chainService,
		}

		request := httptest.NewRequest(http.MethodPost, "http://foo.example", bytes.NewReader([]byte("foo")))
		writer := httptest.NewRecorder()
		writer.Body = &bytes.Buffer{}
		server.ProduceBlockV3(writer, request)
		assert.Equal(t, http.StatusServiceUnavailable, writer.Code)
		assert.Equal(t, true, strings.Contains(writer.Body.String(), "Beacon node is currently syncing and not serving request on that endpoint"))
	})
	t.Run("0 block value is returned on error", func(t *testing.T) {
		rewardFetcher := &rewardtesting.MockBlockRewardFetcher{Error: &httputil.DefaultJsonError{}}

		var block *structs.SignedBeaconBlockContentsFulu
		err := json.Unmarshal([]byte(rpctesting.FuluBlockContents), &block)
		require.NoError(t, err)
		jsonBytes, err := json.Marshal(block.ToUnsigned())
		require.NoError(t, err)
		v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
		v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
			Slot:         1,
			RandaoReveal: bRandao,
			Graffiti:     bGraffiti,
			SkipMevBoost: false,
		}).Return(
			func() (*eth.GenericBeaconBlock, error) {
				b, err := block.ToUnsigned().ToGeneric()
				require.NoError(t, err)
				b.PayloadValue = "2000"
				return b, nil
			}())
		server := &Server{
			V1Alpha1Server:        v1alpha1Server,
			SyncChecker:           syncChecker,
			OptimisticModeFetcher: chainService,
			BlockRewardFetcher:    rewardFetcher,
		}
		request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
		writer := httptest.NewRecorder()
		writer.Body = &bytes.Buffer{}
		server.ProduceBlockV3(writer, request)
		assert.Equal(t, http.StatusOK, writer.Code)
		want := fmt.Sprintf(`{"version":"fulu","execution_payload_blinded":false,"execution_payload_value":"2000","consensus_block_value":"0","data":%s}`, string(jsonBytes))
		body := strings.ReplaceAll(writer.Body.String(), "\n", "")
		require.Equal(t, want, body)
		require.Equal(t, "false", writer.Header().Get(api.ExecutionPayloadBlindedHeader))
		require.Equal(t, "2000", writer.Header().Get(api.ExecutionPayloadValueHeader))
		require.Equal(t, "fulu", writer.Header().Get(api.VersionHeader))
		require.Equal(t, "0", writer.Header().Get(api.ConsensusBlockValueHeader))
	})
}

func TestProduceBlockV3SSZ(t *testing.T) {
	ctrl := gomock.NewController(t)
	randao := "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"
	graffiti := "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
	bRandao, err := hexutil.Decode(randao)
	require.NoError(t, err)
	bGraffiti, err := hexutil.Decode(graffiti)
	require.NoError(t, err)
	chainService := &blockchainTesting.ChainService{}
	syncChecker := &mockSync.Sync{IsSyncing: false}
	rewardFetcher := &rewardtesting.MockBlockRewardFetcher{Rewards: &structs.BlockRewards{Total: "10"}}

	t.Run("Phase 0", func(t *testing.T) {
		var block *structs.SignedBeaconBlock
		err := json.Unmarshal([]byte(rpctesting.Phase0Block), &block)
		require.NoError(t, err)
		v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
		v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
			Slot:         1,
			RandaoReveal: bRandao,
			Graffiti:     bGraffiti,
			SkipMevBoost: false,
		}).Return(
			func() (*eth.GenericBeaconBlock, error) {
				return block.Message.ToGeneric()
			}())
		server := &Server{
			V1Alpha1Server: v1alpha1Server,
			SyncChecker:    syncChecker,
		}
		request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
		request.Header.Set("Accept", api.OctetStreamMediaType)
		writer := httptest.NewRecorder()
		writer.Body = &bytes.Buffer{}
		server.ProduceBlockV3(writer, request)
		assert.Equal(t, http.StatusOK, writer.Code)
		g, err := block.ToGeneric()
		require.NoError(t, err)
		bl, ok := g.Block.(*eth.GenericSignedBeaconBlock_Phase0)
		require.Equal(t, true, ok)
		ssz, err := bl.Phase0.Block.MarshalSSZ()
		require.NoError(t, err)
		require.Equal(t, string(ssz), writer.Body.String())
		require.Equal(t, "false", writer.Header().Get(api.ExecutionPayloadBlindedHeader))
		require.Equal(t, "", writer.Header().Get(api.ExecutionPayloadValueHeader))
		require.Equal(t, "phase0", writer.Header().Get(api.VersionHeader))
		require.Equal(t, "", writer.Header().Get(api.ConsensusBlockValueHeader))
	})
	t.Run("Altair", func(t *testing.T) {
		var block *structs.SignedBeaconBlockAltair
		err := json.Unmarshal([]byte(rpctesting.AltairBlock), &block)
		require.NoError(t, err)
		v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
		v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
			Slot:         1,
			RandaoReveal: bRandao,
			Graffiti:     bGraffiti,
			SkipMevBoost: false,
		}).Return(
			func() (*eth.GenericBeaconBlock, error) {
				return block.Message.ToGeneric()
			}())

		server := &Server{
			V1Alpha1Server:     v1alpha1Server,
			SyncChecker:        syncChecker,
			BlockRewardFetcher: rewardFetcher,
		}
		request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
		request.Header.Set("Accept", api.OctetStreamMediaType)
		writer := httptest.NewRecorder()
		writer.Body = &bytes.Buffer{}
		server.ProduceBlockV3(writer, request)
		assert.Equal(t, http.StatusOK, writer.Code)
		g, err := block.ToGeneric()
		require.NoError(t, err)
		bl, ok := g.Block.(*eth.GenericSignedBeaconBlock_Altair)
		require.Equal(t, true, ok)
		ssz, err := bl.Altair.Block.MarshalSSZ()
		require.NoError(t, err)
		require.Equal(t, string(ssz), writer.Body.String())
		require.Equal(t, "false", writer.Header().Get(api.ExecutionPayloadBlindedHeader))
		require.Equal(t, "", writer.Header().Get(api.ExecutionPayloadValueHeader))
		require.Equal(t, "altair", writer.Header().Get(api.VersionHeader))
		require.Equal(t, "10000000000", writer.Header().Get(api.ConsensusBlockValueHeader))
	})
	t.Run("Bellatrix", func(t *testing.T) {
		var block *structs.SignedBeaconBlockBellatrix
		err := json.Unmarshal([]byte(rpctesting.BellatrixBlock), &block)
		require.NoError(t, err)
		v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
		v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
			Slot:         1,
			RandaoReveal: bRandao,
			Graffiti:     bGraffiti,
			SkipMevBoost: false,
		}).Return(
			func() (*eth.GenericBeaconBlock, error) {
				b, err := block.Message.ToGeneric()
				require.NoError(t, err)
				b.PayloadValue = "2000"
				return b, nil
			}())
		mockChainService := &blockchainTesting.ChainService{}
		server := &Server{
			V1Alpha1Server:        v1alpha1Server,
			SyncChecker:           syncChecker,
			OptimisticModeFetcher: mockChainService,
			BlockRewardFetcher:    rewardFetcher,
		}
		request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
		request.Header.Set("Accept", api.OctetStreamMediaType)
		writer := httptest.NewRecorder()
		writer.Body = &bytes.Buffer{}
		server.ProduceBlockV3(writer, request)
		assert.Equal(t, http.StatusOK, writer.Code)
		g, err := block.ToGeneric()
		require.NoError(t, err)
		bl, ok := g.Block.(*eth.GenericSignedBeaconBlock_Bellatrix)
		require.Equal(t, true, ok)
		ssz, err := bl.Bellatrix.Block.MarshalSSZ()
		require.NoError(t, err)
		require.Equal(t, string(ssz), writer.Body.String())
		require.Equal(t, "false", writer.Header().Get(api.ExecutionPayloadBlindedHeader))
		require.Equal(t, "2000", writer.Header().Get(api.ExecutionPayloadValueHeader))
		require.Equal(t, "bellatrix", writer.Header().Get(api.VersionHeader))
		require.Equal(t, "10000000000", writer.Header().Get(api.ConsensusBlockValueHeader))
	})
	t.Run("BlindedBellatrix", func(t *testing.T) {
		var block *structs.SignedBlindedBeaconBlockBellatrix
		err := json.Unmarshal([]byte(rpctesting.BlindedBellatrixBlock), &block)
		require.NoError(t, err)
		v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
		v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
			Slot:         1,
			RandaoReveal: bRandao,
			Graffiti:     bGraffiti,
			SkipMevBoost: false,
		}).Return(
			func() (*eth.GenericBeaconBlock, error) {
				b, err := block.Message.ToGeneric()
				require.NoError(t, err)
				b.PayloadValue = "2000"
				return b, nil
			}())
		server := &Server{
			V1Alpha1Server:        v1alpha1Server,
			SyncChecker:           syncChecker,
			OptimisticModeFetcher: chainService,
			BlockRewardFetcher:    rewardFetcher,
		}
		request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
		request.Header.Set("Accept", api.OctetStreamMediaType)
		writer := httptest.NewRecorder()
		writer.Body = &bytes.Buffer{}
		server.ProduceBlockV3(writer, request)
		assert.Equal(t, http.StatusOK, writer.Code)
		g, err := block.ToGeneric()
		require.NoError(t, err)
		bl, ok := g.Block.(*eth.GenericSignedBeaconBlock_BlindedBellatrix)
		require.Equal(t, true, ok)
		ssz, err := bl.BlindedBellatrix.Block.MarshalSSZ()
		require.NoError(t, err)
		require.Equal(t, string(ssz), writer.Body.String())
		require.Equal(t, "true", writer.Header().Get(api.ExecutionPayloadBlindedHeader))
		require.Equal(t, "2000", writer.Header().Get(api.ExecutionPayloadValueHeader))
		require.Equal(t, "bellatrix", writer.Header().Get(api.VersionHeader))
		require.Equal(t, "10000000000", writer.Header().Get(api.ConsensusBlockValueHeader))
	})
	t.Run("Capella", func(t *testing.T) {
		var block *structs.SignedBeaconBlockCapella
		err := json.Unmarshal([]byte(rpctesting.CapellaBlock), &block)
		require.NoError(t, err)
		v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
		v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
			Slot:         1,
			RandaoReveal: bRandao,
			Graffiti:     bGraffiti,
			SkipMevBoost: false,
		}).Return(
			func() (*eth.GenericBeaconBlock, error) {
				b, err := block.Message.ToGeneric()
				require.NoError(t, err)
				b.PayloadValue = "2000"
				return b, nil
			}())
		server := &Server{
			V1Alpha1Server:        v1alpha1Server,
			SyncChecker:           syncChecker,
			OptimisticModeFetcher: chainService,
			BlockRewardFetcher:    rewardFetcher,
		}
		request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
		request.Header.Set("Accept", api.OctetStreamMediaType)
		writer := httptest.NewRecorder()
		writer.Body = &bytes.Buffer{}
		server.ProduceBlockV3(writer, request)
		assert.Equal(t, http.StatusOK, writer.Code)
		g, err := block.ToGeneric()
		require.NoError(t, err)
		bl, ok := g.Block.(*eth.GenericSignedBeaconBlock_Capella)
		require.Equal(t, true, ok)
		ssz, err := bl.Capella.Block.MarshalSSZ()
		require.NoError(t, err)
		require.Equal(t, string(ssz), writer.Body.String())
		require.Equal(t, "false", writer.Header().Get(api.ExecutionPayloadBlindedHeader))
		require.Equal(t, "2000", writer.Header().Get(api.ExecutionPayloadValueHeader))
		require.Equal(t, "capella", writer.Header().Get(api.VersionHeader))
		require.Equal(t, "10000000000", writer.Header().Get(api.ConsensusBlockValueHeader))
	})
	t.Run("Blinded Capella", func(t *testing.T) {
		var block *structs.SignedBlindedBeaconBlockCapella
		err := json.Unmarshal([]byte(rpctesting.BlindedCapellaBlock), &block)
		require.NoError(t, err)
		v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
		v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
			Slot:         1,
			RandaoReveal: bRandao,
			Graffiti:     bGraffiti,
			SkipMevBoost: false,
		}).Return(
			func() (*eth.GenericBeaconBlock, error) {
				g, err := block.Message.ToGeneric()
				require.NoError(t, err)
				g.PayloadValue = "2000"
				return g, err
			}())
		server := &Server{
			V1Alpha1Server:        v1alpha1Server,
			SyncChecker:           syncChecker,
			OptimisticModeFetcher: chainService,
			BlockRewardFetcher:    rewardFetcher,
		}
		request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
		request.Header.Set("Accept", api.OctetStreamMediaType)
		writer := httptest.NewRecorder()
		writer.Body = &bytes.Buffer{}
		server.ProduceBlockV3(writer, request)
		assert.Equal(t, http.StatusOK, writer.Code)
		g, err := block.ToGeneric()
		require.NoError(t, err)
		bl, ok := g.Block.(*eth.GenericSignedBeaconBlock_BlindedCapella)
		require.Equal(t, true, ok)
		ssz, err := bl.BlindedCapella.Block.MarshalSSZ()
		require.NoError(t, err)
		require.Equal(t, string(ssz), writer.Body.String())
		require.Equal(t, "true", writer.Header().Get(api.ExecutionPayloadBlindedHeader))
		require.Equal(t, "2000", writer.Header().Get(api.ExecutionPayloadValueHeader))
		require.Equal(t, "capella", writer.Header().Get(api.VersionHeader))
		require.Equal(t, "10000000000", writer.Header().Get(api.ConsensusBlockValueHeader))
	})
	t.Run("Deneb", func(t *testing.T) {
		var block *structs.SignedBeaconBlockContentsDeneb
		err := json.Unmarshal([]byte(rpctesting.DenebBlockContents), &block)
		require.NoError(t, err)
		v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
		v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
			Slot:         1,
			RandaoReveal: bRandao,
			Graffiti:     bGraffiti,
			SkipMevBoost: false,
		}).Return(
			func() (*eth.GenericBeaconBlock, error) {
				b, err := block.ToUnsigned().ToGeneric()
				require.NoError(t, err)
				b.PayloadValue = "2000"
				return b, nil
			}())
		server := &Server{
			V1Alpha1Server:        v1alpha1Server,
			SyncChecker:           syncChecker,
			OptimisticModeFetcher: chainService,
			BlockRewardFetcher:    rewardFetcher,
		}
		request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
		request.Header.Set("Accept", api.OctetStreamMediaType)
		writer := httptest.NewRecorder()
		writer.Body = &bytes.Buffer{}
		server.ProduceBlockV3(writer, request)
		assert.Equal(t, http.StatusOK, writer.Code)
		g, err := block.ToUnsigned().ToGeneric()
		require.NoError(t, err)
		bl, ok := g.Block.(*eth.GenericBeaconBlock_Deneb)
		require.Equal(t, true, ok)
		ssz, err := bl.Deneb.MarshalSSZ()
		require.NoError(t, err)
		require.Equal(t, string(ssz), writer.Body.String())
		require.Equal(t, "false", writer.Header().Get(api.ExecutionPayloadBlindedHeader))
		require.Equal(t, "2000", writer.Header().Get(api.ExecutionPayloadValueHeader))
		require.Equal(t, "deneb", writer.Header().Get(api.VersionHeader))
		require.Equal(t, "10000000000", writer.Header().Get(api.ConsensusBlockValueHeader))
	})
	t.Run("Blinded Deneb", func(t *testing.T) {
		var block *structs.SignedBlindedBeaconBlockDeneb
		err := json.Unmarshal([]byte(rpctesting.BlindedDenebBlock), &block)
		require.NoError(t, err)
		v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
		v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
			Slot:         1,
			RandaoReveal: bRandao,
			Graffiti:     bGraffiti,
			SkipMevBoost: false,
		}).Return(
			func() (*eth.GenericBeaconBlock, error) {
				b, err := block.Message.ToGeneric()
				require.NoError(t, err)
				b.PayloadValue = "2000"
				return b, nil
			}())
		server := &Server{
			V1Alpha1Server:        v1alpha1Server,
			SyncChecker:           syncChecker,
			OptimisticModeFetcher: chainService,
			BlockRewardFetcher:    rewardFetcher,
		}
		request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
		request.Header.Set("Accept", api.OctetStreamMediaType)
		writer := httptest.NewRecorder()
		writer.Body = &bytes.Buffer{}
		server.ProduceBlockV3(writer, request)
		assert.Equal(t, http.StatusOK, writer.Code)
		g, err := block.Message.ToGeneric()
		require.NoError(t, err)
		bl, ok := g.Block.(*eth.GenericBeaconBlock_BlindedDeneb)
		require.Equal(t, true, ok)
		ssz, err := bl.BlindedDeneb.MarshalSSZ()
		require.NoError(t, err)
		require.Equal(t, string(ssz), writer.Body.String())
		require.Equal(t, "true", writer.Header().Get(api.ExecutionPayloadBlindedHeader))
		require.Equal(t, "2000", writer.Header().Get(api.ExecutionPayloadValueHeader))
		require.Equal(t, "deneb", writer.Header().Get(api.VersionHeader))
		require.Equal(t, "10000000000", writer.Header().Get(api.ConsensusBlockValueHeader))
	})
	t.Run("Electra", func(t *testing.T) {
		var block *structs.SignedBeaconBlockContentsElectra
		err := json.Unmarshal([]byte(rpctesting.ElectraBlockContents), &block)
		require.NoError(t, err)
		v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
		v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
			Slot:         1,
			RandaoReveal: bRandao,
			Graffiti:     bGraffiti,
			SkipMevBoost: false,
		}).Return(
			func() (*eth.GenericBeaconBlock, error) {
				b, err := block.ToUnsigned().ToGeneric()
				require.NoError(t, err)
				b.PayloadValue = "2000"
				return b, nil
			}())
		server := &Server{
			V1Alpha1Server:        v1alpha1Server,
			SyncChecker:           syncChecker,
			OptimisticModeFetcher: chainService,
			BlockRewardFetcher:    rewardFetcher,
		}
		request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
		request.Header.Set("Accept", api.OctetStreamMediaType)
		writer := httptest.NewRecorder()
		writer.Body = &bytes.Buffer{}
		server.ProduceBlockV3(writer, request)
		assert.Equal(t, http.StatusOK, writer.Code)
		g, err := block.ToUnsigned().ToGeneric()
		require.NoError(t, err)
		bl, ok := g.Block.(*eth.GenericBeaconBlock_Electra)
		require.Equal(t, true, ok)
		ssz, err := bl.Electra.MarshalSSZ()
		require.NoError(t, err)
		require.Equal(t, string(ssz), writer.Body.String())
		require.Equal(t, "false", writer.Header().Get(api.ExecutionPayloadBlindedHeader))
		require.Equal(t, "2000", writer.Header().Get(api.ExecutionPayloadValueHeader))
		require.Equal(t, "electra", writer.Header().Get(api.VersionHeader))
		require.Equal(t, "10000000000", writer.Header().Get(api.ConsensusBlockValueHeader))
	})
	t.Run("Blinded Electra", func(t *testing.T) {
		var block *structs.SignedBlindedBeaconBlockElectra
		err := json.Unmarshal([]byte(rpctesting.BlindedElectraBlock), &block)
		require.NoError(t, err)
		v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
		v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
			Slot:         1,
			RandaoReveal: bRandao,
			Graffiti:     bGraffiti,
			SkipMevBoost: false,
		}).Return(
			func() (*eth.GenericBeaconBlock, error) {
				b, err := block.Message.ToGeneric()
				require.NoError(t, err)
				b.PayloadValue = "2000"
				return b, nil
			}())
		server := &Server{
			V1Alpha1Server:        v1alpha1Server,
			SyncChecker:           syncChecker,
			OptimisticModeFetcher: chainService,
			BlockRewardFetcher:    rewardFetcher,
		}
		request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
		request.Header.Set("Accept", api.OctetStreamMediaType)
		writer := httptest.NewRecorder()
		writer.Body = &bytes.Buffer{}
		server.ProduceBlockV3(writer, request)
		assert.Equal(t, http.StatusOK, writer.Code)
		g, err := block.Message.ToGeneric()
		require.NoError(t, err)
		bl, ok := g.Block.(*eth.GenericBeaconBlock_BlindedElectra)
		require.Equal(t, true, ok)
		ssz, err := bl.BlindedElectra.MarshalSSZ()
		require.NoError(t, err)
		require.Equal(t, string(ssz), writer.Body.String())
		require.Equal(t, "true", writer.Header().Get(api.ExecutionPayloadBlindedHeader))
		require.Equal(t, "2000", writer.Header().Get(api.ExecutionPayloadValueHeader))
		require.Equal(t, "electra", writer.Header().Get(api.VersionHeader))
		require.Equal(t, "10000000000", writer.Header().Get(api.ConsensusBlockValueHeader))
	})
	t.Run("Fulu", func(t *testing.T) {
		var block *structs.SignedBeaconBlockContentsFulu
		err := json.Unmarshal([]byte(rpctesting.FuluBlockContents), &block)
		require.NoError(t, err)
		v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
		v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
			Slot:         1,
			RandaoReveal: bRandao,
			Graffiti:     bGraffiti,
			SkipMevBoost: false,
		}).Return(
			func() (*eth.GenericBeaconBlock, error) {
				b, err := block.ToUnsigned().ToGeneric()
				require.NoError(t, err)
				b.PayloadValue = "2000"
				return b, nil
			}())
		server := &Server{
			V1Alpha1Server:        v1alpha1Server,
			SyncChecker:           syncChecker,
			OptimisticModeFetcher: chainService,
			BlockRewardFetcher:    rewardFetcher,
		}
		request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
		request.Header.Set("Accept", api.OctetStreamMediaType)
		writer := httptest.NewRecorder()
		writer.Body = &bytes.Buffer{}
		server.ProduceBlockV3(writer, request)
		assert.Equal(t, http.StatusOK, writer.Code)
		g, err := block.ToUnsigned().ToGeneric()
		require.NoError(t, err)
		bl, ok := g.Block.(*eth.GenericBeaconBlock_Fulu)
		require.Equal(t, true, ok)
		ssz, err := bl.Fulu.MarshalSSZ()
		require.NoError(t, err)
		require.Equal(t, string(ssz), writer.Body.String())
		require.Equal(t, "false", writer.Header().Get(api.ExecutionPayloadBlindedHeader))
		require.Equal(t, "2000", writer.Header().Get(api.ExecutionPayloadValueHeader))
		require.Equal(t, "fulu", writer.Header().Get(api.VersionHeader))
		require.Equal(t, "10000000000", writer.Header().Get(api.ConsensusBlockValueHeader))
	})
	t.Run("Blinded Fulu", func(t *testing.T) {
		var block *structs.SignedBlindedBeaconBlockFulu
		err := json.Unmarshal([]byte(rpctesting.BlindedFuluBlock), &block)
		require.NoError(t, err)
		v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
		v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
			Slot:         1,
			RandaoReveal: bRandao,
			Graffiti:     bGraffiti,
			SkipMevBoost: false,
		}).Return(
			func() (*eth.GenericBeaconBlock, error) {
				b, err := block.Message.ToGeneric()
				require.NoError(t, err)
				b.PayloadValue = "2000"
				return b, nil
			}())
		server := &Server{
			V1Alpha1Server:        v1alpha1Server,
			SyncChecker:           syncChecker,
			OptimisticModeFetcher: chainService,
			BlockRewardFetcher:    rewardFetcher,
		}
		request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
		request.Header.Set("Accept", api.OctetStreamMediaType)
		writer := httptest.NewRecorder()
		writer.Body = &bytes.Buffer{}
		server.ProduceBlockV3(writer, request)
		assert.Equal(t, http.StatusOK, writer.Code)
		g, err := block.Message.ToGeneric()
		require.NoError(t, err)
		bl, ok := g.Block.(*eth.GenericBeaconBlock_BlindedFulu)
		require.Equal(t, true, ok)
		ssz, err := bl.BlindedFulu.MarshalSSZ()
		require.NoError(t, err)
		require.Equal(t, string(ssz), writer.Body.String())
		require.Equal(t, "true", writer.Header().Get(api.ExecutionPayloadBlindedHeader))
		require.Equal(t, "2000", writer.Header().Get(api.ExecutionPayloadValueHeader))
		require.Equal(t, "fulu", writer.Header().Get(api.VersionHeader))
		require.Equal(t, "10000000000", writer.Header().Get(api.ConsensusBlockValueHeader))
	})
	t.Run("0 block value is returned on error", func(t *testing.T) {
		rewardFetcher := &rewardtesting.MockBlockRewardFetcher{Error: &httputil.DefaultJsonError{}}

		var block *structs.SignedBeaconBlockContentsFulu
		err := json.Unmarshal([]byte(rpctesting.FuluBlockContents), &block)
		require.NoError(t, err)
		v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
		v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), &eth.BlockRequest{
			Slot:         1,
			RandaoReveal: bRandao,
			Graffiti:     bGraffiti,
			SkipMevBoost: false,
		}).Return(
			func() (*eth.GenericBeaconBlock, error) {
				b, err := block.ToUnsigned().ToGeneric()
				require.NoError(t, err)
				b.PayloadValue = "2000"
				return b, nil
			}())
		server := &Server{
			V1Alpha1Server:        v1alpha1Server,
			SyncChecker:           syncChecker,
			OptimisticModeFetcher: chainService,
			BlockRewardFetcher:    rewardFetcher,
		}
		request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
		request.Header.Set("Accept", api.OctetStreamMediaType)
		writer := httptest.NewRecorder()
		writer.Body = &bytes.Buffer{}
		server.ProduceBlockV3(writer, request)
		assert.Equal(t, http.StatusOK, writer.Code)
		g, err := block.ToUnsigned().ToGeneric()
		require.NoError(t, err)
		bl, ok := g.Block.(*eth.GenericBeaconBlock_Fulu)
		require.Equal(t, true, ok)
		ssz, err := bl.Fulu.MarshalSSZ()
		require.NoError(t, err)
		require.Equal(t, string(ssz), writer.Body.String())
		require.Equal(t, "false", writer.Header().Get(api.ExecutionPayloadBlindedHeader))
		require.Equal(t, "2000", writer.Header().Get(api.ExecutionPayloadValueHeader))
		require.Equal(t, "fulu", writer.Header().Get(api.VersionHeader))
		require.Equal(t, "0", writer.Header().Get(api.ConsensusBlockValueHeader))
	})
}
