From 47fe2d33555d4b341f38d444b91b474fb56778cb Mon Sep 17 00:00:00 2001 From: Inspector-Butters Date: Tue, 8 Oct 2024 16:39:22 +0200 Subject: [PATCH 01/12] change updatebyrange --- beacon-chain/rpc/eth/light-client/handlers.go | 112 +++--------------- 1 file changed, 15 insertions(+), 97 deletions(-) diff --git a/beacon-chain/rpc/eth/light-client/handlers.go b/beacon-chain/rpc/eth/light-client/handlers.go index 245d703eaafd..4fcf91eb0189 100644 --- a/beacon-chain/rpc/eth/light-client/handlers.go +++ b/beacon-chain/rpc/eth/light-client/handlers.go @@ -11,10 +11,8 @@ import ( "github.com/prysmaticlabs/prysm/v5/api" "github.com/prysmaticlabs/prysm/v5/api/server/structs" "github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/eth/shared" - "github.com/prysmaticlabs/prysm/v5/beacon-chain/state" "github.com/prysmaticlabs/prysm/v5/config/params" "github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces" - types "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace" "github.com/prysmaticlabs/prysm/v5/network/httputil" "github.com/prysmaticlabs/prysm/v5/runtime/version" @@ -117,108 +115,28 @@ func (s *Server) GetLightClientUpdatesByRange(w http.ResponseWriter, req *http.R endPeriod = maxSlot / slotsPerPeriod } - // Populate updates - var updates []*structs.LightClientUpdateResponse - for period := startPeriod; period <= endPeriod; period++ { - // Get the last known state of the period, - // 1. We wish the block has a parent in the same period if possible - // 2. We wish the block has a state in the same period - lastSlotInPeriod := period*slotsPerPeriod + slotsPerPeriod - 1 - if lastSlotInPeriod > maxSlot { - lastSlotInPeriod = maxSlot - } - firstSlotInPeriod := period * slotsPerPeriod - - // Let's not use the first slot in the period, otherwise the attested header will be in previous period - firstSlotInPeriod++ - - var state state.BeaconState - var block interfaces.ReadOnlySignedBeaconBlock - for slot := lastSlotInPeriod; slot >= firstSlotInPeriod; slot-- { - state, err = s.Stater.StateBySlot(ctx, types.Slot(slot)) - if err != nil { - continue - } - - // Get the block - latestBlockHeader := state.LatestBlockHeader() - latestStateRoot, err := state.HashTreeRoot(ctx) - if err != nil { - continue - } - latestBlockHeader.StateRoot = latestStateRoot[:] - blockRoot, err := latestBlockHeader.HashTreeRoot() - if err != nil { - continue - } - - block, err = s.Blocker.Block(ctx, blockRoot[:]) - if err != nil || block == nil { - continue - } - - syncAggregate, err := block.Block().Body().SyncAggregate() - if err != nil || syncAggregate == nil { - continue - } - - if syncAggregate.SyncCommitteeBits.Count()*3 < config.SyncCommitteeSize*2 { - // Not enough votes - continue - } + // get updates + updatesMap, err := s.BeaconDB.LightClientUpdates(ctx, startPeriod, endPeriod) + if err != nil { + httputil.HandleError(w, "could not get light client updates: "+err.Error(), http.StatusInternalServerError) + return + } + updates := make([]*structs.LightClientUpdateResponse, len(updatesMap)) + for i, j := startPeriod, 0; i <= endPeriod; i, j = i+1, j+1 { + update, ok := updatesMap[i] + if !ok { + // Only return the first contiguous range of updates break } - if block == nil { - // No valid block found for the period - continue - } - - // Get attested state - attestedRoot := block.Block().ParentRoot() - attestedBlock, err := s.Blocker.Block(ctx, attestedRoot[:]) - if err != nil || attestedBlock == nil { - continue - } - - attestedSlot := attestedBlock.Block().Slot() - attestedState, err := s.Stater.StateBySlot(ctx, attestedSlot) + updateResponse, err := structs.LightClientUpdateResponseFromConsensus(update) if err != nil { - continue - } - - // Get finalized block - var finalizedBlock interfaces.ReadOnlySignedBeaconBlock - finalizedCheckPoint := attestedState.FinalizedCheckpoint() - if finalizedCheckPoint != nil { - finalizedRoot := bytesutil.ToBytes32(finalizedCheckPoint.Root) - finalizedBlock, err = s.Blocker.Block(ctx, finalizedRoot[:]) - if err != nil { - finalizedBlock = nil - } + httputil.HandleError(w, "could not convert light client update: "+err.Error(), http.StatusInternalServerError) + return } - update, err := newLightClientUpdateFromBeaconState( - ctx, - state, - block, - attestedState, - attestedBlock, - finalizedBlock, - ) - - if err == nil { - updates = append(updates, &structs.LightClientUpdateResponse{ - Version: version.String(attestedState.Version()), - Data: update, - }) - } - } - - if len(updates) == 0 { - httputil.HandleError(w, "no updates found", http.StatusNotFound) - return + updates[j] = updateResponse } httputil.WriteJson(w, updates) From b446e03693917b9d6c0d36a64b3be9dab78359e2 Mon Sep 17 00:00:00 2001 From: Inspector-Butters Date: Tue, 8 Oct 2024 16:40:45 +0200 Subject: [PATCH 02/12] lcupdateresponse from consensus --- api/server/structs/conversions_lightclient.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/api/server/structs/conversions_lightclient.go b/api/server/structs/conversions_lightclient.go index 50e6281ef9b9..662266f01172 100644 --- a/api/server/structs/conversions_lightclient.go +++ b/api/server/structs/conversions_lightclient.go @@ -10,8 +10,21 @@ import ( v1 "github.com/prysmaticlabs/prysm/v5/proto/eth/v1" v2 "github.com/prysmaticlabs/prysm/v5/proto/eth/v2" "github.com/prysmaticlabs/prysm/v5/proto/migration" + "github.com/prysmaticlabs/prysm/v5/runtime/version" ) +func LightClientUpdateResponseFromConsensus(update *v2.LightClientUpdateWithVersion) (*LightClientUpdateResponse, error) { + data, err := LightClientUpdateFromConsensus(update.Data) + if err != nil { + return nil, err + } + + return &LightClientUpdateResponse{ + Version: version.String(int(update.Version)), + Data: data, + }, nil +} + func LightClientUpdateFromConsensus(update *v2.LightClientUpdate) (*LightClientUpdate, error) { attestedHeader, err := lightClientHeaderContainerToJSON(update.AttestedHeader) if err != nil { From 5689d45ae1aba24d14b7d31103369c32bcff0c93 Mon Sep 17 00:00:00 2001 From: Inspector-Butters Date: Thu, 10 Oct 2024 12:40:58 +0200 Subject: [PATCH 03/12] range altair test --- api/server/structs/BUILD.bazel | 1 + beacon-chain/rpc/eth/light-client/BUILD.bazel | 1 - .../rpc/eth/light-client/handlers_test.go | 1588 +++++++++-------- 3 files changed, 843 insertions(+), 747 deletions(-) diff --git a/api/server/structs/BUILD.bazel b/api/server/structs/BUILD.bazel index c194d502ee02..d6532e7bcdee 100644 --- a/api/server/structs/BUILD.bazel +++ b/api/server/structs/BUILD.bazel @@ -39,6 +39,7 @@ go_library( "//proto/eth/v2:go_default_library", "//proto/migration:go_default_library", "//proto/prysm/v1alpha1:go_default_library", + "//runtime/version:go_default_library", "@com_github_ethereum_go_ethereum//common:go_default_library", "@com_github_ethereum_go_ethereum//common/hexutil:go_default_library", "@com_github_pkg_errors//:go_default_library", diff --git a/beacon-chain/rpc/eth/light-client/BUILD.bazel b/beacon-chain/rpc/eth/light-client/BUILD.bazel index 85b46a07ecc4..d21b3b2ebc03 100644 --- a/beacon-chain/rpc/eth/light-client/BUILD.bazel +++ b/beacon-chain/rpc/eth/light-client/BUILD.bazel @@ -21,7 +21,6 @@ go_library( "//config/fieldparams:go_default_library", "//config/params:go_default_library", "//consensus-types/interfaces:go_default_library", - "//consensus-types/primitives:go_default_library", "//monitoring/tracing/trace:go_default_library", "//network/httputil:go_default_library", "//proto/eth/v2:go_default_library", diff --git a/beacon-chain/rpc/eth/light-client/handlers_test.go b/beacon-chain/rpc/eth/light-client/handlers_test.go index 342ea679ee3c..b32e923c8f68 100644 --- a/beacon-chain/rpc/eth/light-client/handlers_test.go +++ b/beacon-chain/rpc/eth/light-client/handlers_test.go @@ -14,13 +14,18 @@ import ( "github.com/prysmaticlabs/prysm/v5/api/server/structs" mock "github.com/prysmaticlabs/prysm/v5/beacon-chain/blockchain/testing" "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers" + "github.com/prysmaticlabs/prysm/v5/beacon-chain/db/kv" "github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/testutil" "github.com/prysmaticlabs/prysm/v5/beacon-chain/state" "github.com/prysmaticlabs/prysm/v5/config/params" "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks" "github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces" "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" + enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1" + ethpbv1 "github.com/prysmaticlabs/prysm/v5/proto/eth/v1" + ethpbv2 "github.com/prysmaticlabs/prysm/v5/proto/eth/v2" ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/prysm/v5/runtime/version" "github.com/prysmaticlabs/prysm/v5/testing/require" "github.com/prysmaticlabs/prysm/v5/testing/util" ) @@ -291,536 +296,42 @@ func TestLightClientHandler_GetLightClientUpdatesByRangeAltair(t *testing.T) { root, err := block.Block.HashTreeRoot() require.NoError(t, err) - mockBlocker := &testutil.MockBlocker{ - RootBlockMap: map[[32]byte]interfaces.ReadOnlySignedBeaconBlock{ - parentRoot: signedParent, - root: signedBlock, - }, - SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{ - slot.Sub(1): signedParent, - slot: signedBlock, - }, - } - mockChainService := &mock.ChainService{Optimistic: true, Slot: &slot, State: st} - s := &Server{ - Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{ - slot.Sub(1): attestedState, - slot: st, - }}, - Blocker: mockBlocker, - HeadFetcher: mockChainService, - } - startPeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) - url := fmt.Sprintf("http://foo.com/?count=1&start_period=%d", startPeriod) - request := httptest.NewRequest("GET", url, nil) - writer := httptest.NewRecorder() - writer.Body = &bytes.Buffer{} - - s.GetLightClientUpdatesByRange(writer, request) - - require.Equal(t, http.StatusOK, writer.Code) - var resp structs.LightClientUpdatesByRangeResponse - err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) - require.NoError(t, err) - var respHeader structs.LightClientHeader - err = json.Unmarshal(resp.Updates[0].Data.AttestedHeader, &respHeader) - require.NoError(t, err) - require.Equal(t, 1, len(resp.Updates)) - require.Equal(t, "altair", resp.Updates[0].Version) - require.Equal(t, hexutil.Encode(attestedHeader.BodyRoot), respHeader.Beacon.BodyRoot) - require.NotNil(t, resp) -} - -func TestLightClientHandler_GetLightClientUpdatesByRangeCapella(t *testing.T) { - helpers.ClearCache() - ctx := context.Background() - config := params.BeaconConfig() - slot := primitives.Slot(config.CapellaForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) - - attestedState, err := util.NewBeaconStateCapella() - require.NoError(t, err) - err = attestedState.SetSlot(slot.Sub(1)) - require.NoError(t, err) - - parent := util.NewBeaconBlockCapella() - parent.Block.Slot = slot.Sub(1) - - signedParent, err := blocks.NewSignedBeaconBlock(parent) - require.NoError(t, err) - - parentHeader, err := signedParent.Header() - require.NoError(t, err) - attestedHeader := parentHeader.Header - - err = attestedState.SetLatestBlockHeader(attestedHeader) - require.NoError(t, err) - attestedStateRoot, err := attestedState.HashTreeRoot(ctx) - require.NoError(t, err) - - // get a new signed block so the root is updated with the new state root - parent.Block.StateRoot = attestedStateRoot[:] - signedParent, err = blocks.NewSignedBeaconBlock(parent) - require.NoError(t, err) - - st, err := util.NewBeaconStateCapella() - require.NoError(t, err) - err = st.SetSlot(slot) - require.NoError(t, err) - - parentRoot, err := signedParent.Block().HashTreeRoot() - require.NoError(t, err) - - block := util.NewBeaconBlockCapella() - block.Block.Slot = slot - block.Block.ParentRoot = parentRoot[:] - - for i := uint64(0); i < config.SyncCommitteeSize; i++ { - block.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true) - } - - signedBlock, err := blocks.NewSignedBeaconBlock(block) - require.NoError(t, err) - - h, err := signedBlock.Header() - require.NoError(t, err) - - err = st.SetLatestBlockHeader(h.Header) - require.NoError(t, err) - stateRoot, err := st.HashTreeRoot(ctx) - require.NoError(t, err) - - // get a new signed block so the root is updated with the new state root - block.Block.StateRoot = stateRoot[:] - signedBlock, err = blocks.NewSignedBeaconBlock(block) - require.NoError(t, err) - - root, err := block.Block.HashTreeRoot() - require.NoError(t, err) - - mockBlocker := &testutil.MockBlocker{ - RootBlockMap: map[[32]byte]interfaces.ReadOnlySignedBeaconBlock{ - parentRoot: signedParent, - root: signedBlock, - }, - SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{ - slot.Sub(1): signedParent, - slot: signedBlock, - }, - } - mockChainService := &mock.ChainService{Optimistic: true, Slot: &slot, State: st} - s := &Server{ - Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{ - slot.Sub(1): attestedState, - slot: st, - }}, - Blocker: mockBlocker, - HeadFetcher: mockChainService, - } - startPeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) - url := fmt.Sprintf("http://foo.com/?count=1&start_period=%d", startPeriod) - request := httptest.NewRequest("GET", url, nil) - writer := httptest.NewRecorder() - writer.Body = &bytes.Buffer{} - - s.GetLightClientUpdatesByRange(writer, request) - - require.Equal(t, http.StatusOK, writer.Code) - var resp structs.LightClientUpdatesByRangeResponse - err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) - require.NoError(t, err) - var respHeader structs.LightClientHeaderCapella - err = json.Unmarshal(resp.Updates[0].Data.AttestedHeader, &respHeader) - require.NoError(t, err) - require.Equal(t, 1, len(resp.Updates)) - require.Equal(t, "capella", resp.Updates[0].Version) - require.Equal(t, hexutil.Encode(attestedHeader.BodyRoot), respHeader.Beacon.BodyRoot) - require.NotNil(t, resp) -} - -func TestLightClientHandler_GetLightClientUpdatesByRangeDeneb(t *testing.T) { - helpers.ClearCache() - ctx := context.Background() - config := params.BeaconConfig() - slot := primitives.Slot(config.DenebForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) - - attestedState, err := util.NewBeaconStateDeneb() - require.NoError(t, err) - err = attestedState.SetSlot(slot.Sub(1)) - require.NoError(t, err) - - parent := util.NewBeaconBlockDeneb() - parent.Block.Slot = slot.Sub(1) - - signedParent, err := blocks.NewSignedBeaconBlock(parent) - require.NoError(t, err) - - parentHeader, err := signedParent.Header() - require.NoError(t, err) - attestedHeader := parentHeader.Header - - err = attestedState.SetLatestBlockHeader(attestedHeader) - require.NoError(t, err) - attestedStateRoot, err := attestedState.HashTreeRoot(ctx) - require.NoError(t, err) - - // get a new signed block so the root is updated with the new state root - parent.Block.StateRoot = attestedStateRoot[:] - signedParent, err = blocks.NewSignedBeaconBlock(parent) - require.NoError(t, err) - - st, err := util.NewBeaconStateDeneb() - require.NoError(t, err) - err = st.SetSlot(slot) - require.NoError(t, err) - - parentRoot, err := signedParent.Block().HashTreeRoot() - require.NoError(t, err) - - block := util.NewBeaconBlockDeneb() - block.Block.Slot = slot - block.Block.ParentRoot = parentRoot[:] - - for i := uint64(0); i < config.SyncCommitteeSize; i++ { - block.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true) - } - - signedBlock, err := blocks.NewSignedBeaconBlock(block) - require.NoError(t, err) - - h, err := signedBlock.Header() - require.NoError(t, err) - - err = st.SetLatestBlockHeader(h.Header) - require.NoError(t, err) - stateRoot, err := st.HashTreeRoot(ctx) - require.NoError(t, err) - - // get a new signed block so the root is updated with the new state root - block.Block.StateRoot = stateRoot[:] - signedBlock, err = blocks.NewSignedBeaconBlock(block) - require.NoError(t, err) - - root, err := block.Block.HashTreeRoot() - require.NoError(t, err) - - mockBlocker := &testutil.MockBlocker{ - RootBlockMap: map[[32]byte]interfaces.ReadOnlySignedBeaconBlock{ - parentRoot: signedParent, - root: signedBlock, - }, - SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{ - slot.Sub(1): signedParent, - slot: signedBlock, - }, - } - mockChainService := &mock.ChainService{Optimistic: true, Slot: &slot, State: st} - s := &Server{ - Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{ - slot.Sub(1): attestedState, - slot: st, - }}, - Blocker: mockBlocker, - HeadFetcher: mockChainService, - } - startPeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) - url := fmt.Sprintf("http://foo.com/?count=1&start_period=%d", startPeriod) - request := httptest.NewRequest("GET", url, nil) - writer := httptest.NewRecorder() - writer.Body = &bytes.Buffer{} - - s.GetLightClientUpdatesByRange(writer, request) - - require.Equal(t, http.StatusOK, writer.Code) - var resp structs.LightClientUpdatesByRangeResponse - err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) - require.NoError(t, err) - var respHeader structs.LightClientHeaderDeneb - err = json.Unmarshal(resp.Updates[0].Data.AttestedHeader, &respHeader) - require.NoError(t, err) - require.Equal(t, 1, len(resp.Updates)) - require.Equal(t, "deneb", resp.Updates[0].Version) - require.Equal(t, hexutil.Encode(attestedHeader.BodyRoot), respHeader.Beacon.BodyRoot) - require.NotNil(t, resp) -} - -func TestLightClientHandler_GetLightClientUpdatesByRange_TooBigInputCountAltair(t *testing.T) { - helpers.ClearCache() - ctx := context.Background() - config := params.BeaconConfig() - slot := primitives.Slot(config.AltairForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) - - attestedState, err := util.NewBeaconStateAltair() - require.NoError(t, err) - err = attestedState.SetSlot(slot.Sub(1)) - require.NoError(t, err) - - parent := util.NewBeaconBlockAltair() - parent.Block.Slot = slot.Sub(1) - - signedParent, err := blocks.NewSignedBeaconBlock(parent) - require.NoError(t, err) - - parentHeader, err := signedParent.Header() - require.NoError(t, err) - attestedHeader := parentHeader.Header - - err = attestedState.SetLatestBlockHeader(attestedHeader) - require.NoError(t, err) - attestedStateRoot, err := attestedState.HashTreeRoot(ctx) - require.NoError(t, err) - - // get a new signed block so the root is updated with the new state root - parent.Block.StateRoot = attestedStateRoot[:] - signedParent, err = blocks.NewSignedBeaconBlock(parent) - require.NoError(t, err) - - st, err := util.NewBeaconStateAltair() - require.NoError(t, err) - err = st.SetSlot(slot) - require.NoError(t, err) - - parentRoot, err := signedParent.Block().HashTreeRoot() - require.NoError(t, err) - - block := util.NewBeaconBlockAltair() - block.Block.Slot = slot - block.Block.ParentRoot = parentRoot[:] - - for i := uint64(0); i < config.SyncCommitteeSize; i++ { - block.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true) - } - - signedBlock, err := blocks.NewSignedBeaconBlock(block) - require.NoError(t, err) - - h, err := signedBlock.Header() - require.NoError(t, err) - - err = st.SetLatestBlockHeader(h.Header) - require.NoError(t, err) - stateRoot, err := st.HashTreeRoot(ctx) - require.NoError(t, err) - - // get a new signed block so the root is updated with the new state root - block.Block.StateRoot = stateRoot[:] - signedBlock, err = blocks.NewSignedBeaconBlock(block) - require.NoError(t, err) - - root, err := block.Block.HashTreeRoot() - require.NoError(t, err) - - mockBlocker := &testutil.MockBlocker{ - RootBlockMap: map[[32]byte]interfaces.ReadOnlySignedBeaconBlock{ - parentRoot: signedParent, - root: signedBlock, - }, - SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{ - slot.Sub(1): signedParent, - slot: signedBlock, - }, - } - mockChainService := &mock.ChainService{Optimistic: true, Slot: &slot, State: st} - s := &Server{ - Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{ - slot.Sub(1): attestedState, - slot: st, - }}, - Blocker: mockBlocker, - HeadFetcher: mockChainService, - } - startPeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) - count := 129 // config.MaxRequestLightClientUpdates is 128 - url := fmt.Sprintf("http://foo.com/?count=%d&start_period=%d", count, startPeriod) - request := httptest.NewRequest("GET", url, nil) - writer := httptest.NewRecorder() - writer.Body = &bytes.Buffer{} - - s.GetLightClientUpdatesByRange(writer, request) - - require.Equal(t, http.StatusOK, writer.Code) - var resp structs.LightClientUpdatesByRangeResponse - err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) - require.NoError(t, err) - var respHeader structs.LightClientHeader - err = json.Unmarshal(resp.Updates[0].Data.AttestedHeader, &respHeader) - require.NoError(t, err) - require.Equal(t, 1, len(resp.Updates)) // Even with big count input, the response is still the max available period, which is 1 in test case. - require.Equal(t, "altair", resp.Updates[0].Version) - require.Equal(t, hexutil.Encode(attestedHeader.BodyRoot), respHeader.Beacon.BodyRoot) - require.NotNil(t, resp) -} - -func TestLightClientHandler_GetLightClientUpdatesByRange_TooBigInputCountCapella(t *testing.T) { - helpers.ClearCache() - ctx := context.Background() - config := params.BeaconConfig() - slot := primitives.Slot(config.CapellaForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) - - attestedState, err := util.NewBeaconStateCapella() - require.NoError(t, err) - err = attestedState.SetSlot(slot.Sub(1)) - require.NoError(t, err) - - parent := util.NewBeaconBlockCapella() - parent.Block.Slot = slot.Sub(1) - - signedParent, err := blocks.NewSignedBeaconBlock(parent) - require.NoError(t, err) - - parentHeader, err := signedParent.Header() - require.NoError(t, err) - attestedHeader := parentHeader.Header - - err = attestedState.SetLatestBlockHeader(attestedHeader) - require.NoError(t, err) - attestedStateRoot, err := attestedState.HashTreeRoot(ctx) - require.NoError(t, err) - - // get a new signed block so the root is updated with the new state root - parent.Block.StateRoot = attestedStateRoot[:] - signedParent, err = blocks.NewSignedBeaconBlock(parent) - require.NoError(t, err) - - st, err := util.NewBeaconStateCapella() - require.NoError(t, err) - err = st.SetSlot(slot) - require.NoError(t, err) - - parentRoot, err := signedParent.Block().HashTreeRoot() - require.NoError(t, err) - - block := util.NewBeaconBlockCapella() - block.Block.Slot = slot - block.Block.ParentRoot = parentRoot[:] - - for i := uint64(0); i < config.SyncCommitteeSize; i++ { - block.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true) - } - - signedBlock, err := blocks.NewSignedBeaconBlock(block) - require.NoError(t, err) - - h, err := signedBlock.Header() - require.NoError(t, err) - - err = st.SetLatestBlockHeader(h.Header) - require.NoError(t, err) - stateRoot, err := st.HashTreeRoot(ctx) - require.NoError(t, err) - - // get a new signed block so the root is updated with the new state root - block.Block.StateRoot = stateRoot[:] - signedBlock, err = blocks.NewSignedBeaconBlock(block) - require.NoError(t, err) - - root, err := block.Block.HashTreeRoot() - require.NoError(t, err) - - mockBlocker := &testutil.MockBlocker{ - RootBlockMap: map[[32]byte]interfaces.ReadOnlySignedBeaconBlock{ - parentRoot: signedParent, - root: signedBlock, - }, - SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{ - slot.Sub(1): signedParent, - slot: signedBlock, - }, - } - mockChainService := &mock.ChainService{Optimistic: true, Slot: &slot, State: st} - s := &Server{ - Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{ - slot.Sub(1): attestedState, - slot: st, - }}, - Blocker: mockBlocker, - HeadFetcher: mockChainService, - } - startPeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) - count := 129 // config.MaxRequestLightClientUpdates is 128 - url := fmt.Sprintf("http://foo.com/?count=%d&start_period=%d", count, startPeriod) - request := httptest.NewRequest("GET", url, nil) - writer := httptest.NewRecorder() - writer.Body = &bytes.Buffer{} - - s.GetLightClientUpdatesByRange(writer, request) - - require.Equal(t, http.StatusOK, writer.Code) - var resp structs.LightClientUpdatesByRangeResponse - err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) - require.NoError(t, err) - var respHeader structs.LightClientHeaderCapella - err = json.Unmarshal(resp.Updates[0].Data.AttestedHeader, &respHeader) - require.NoError(t, err) - require.Equal(t, 1, len(resp.Updates)) // Even with big count input, the response is still the max available period, which is 1 in test case. - require.Equal(t, "capella", resp.Updates[0].Version) - require.Equal(t, hexutil.Encode(attestedHeader.BodyRoot), respHeader.Beacon.BodyRoot) - require.NotNil(t, resp) -} - -func TestLightClientHandler_GetLightClientUpdatesByRange_TooBigInputCountDeneb(t *testing.T) { - helpers.ClearCache() - ctx := context.Background() - config := params.BeaconConfig() - slot := primitives.Slot(config.DenebForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) - - attestedState, err := util.NewBeaconStateDeneb() - require.NoError(t, err) - err = attestedState.SetSlot(slot.Sub(1)) - require.NoError(t, err) - - parent := util.NewBeaconBlockDeneb() - parent.Block.Slot = slot.Sub(1) - - signedParent, err := blocks.NewSignedBeaconBlock(parent) - require.NoError(t, err) - - parentHeader, err := signedParent.Header() - require.NoError(t, err) - attestedHeader := parentHeader.Header - - err = attestedState.SetLatestBlockHeader(attestedHeader) - require.NoError(t, err) - attestedStateRoot, err := attestedState.HashTreeRoot(ctx) - require.NoError(t, err) + db := setupDB(t) - // get a new signed block so the root is updated with the new state root - parent.Block.StateRoot = attestedStateRoot[:] - signedParent, err = blocks.NewSignedBeaconBlock(parent) - require.NoError(t, err) - - st, err := util.NewBeaconStateDeneb() - require.NoError(t, err) - err = st.SetSlot(slot) - require.NoError(t, err) - - parentRoot, err := signedParent.Block().HashTreeRoot() - require.NoError(t, err) - - block := util.NewBeaconBlockDeneb() - block.Block.Slot = slot - block.Block.ParentRoot = parentRoot[:] + updatePeriod := uint64(slot.Sub(1).Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch))) - for i := uint64(0); i < config.SyncCommitteeSize; i++ { - block.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true) + update := ðpbv2.LightClientUpdate{ + AttestedHeader: ðpbv2.LightClientHeaderContainer{ + Header: ðpbv2.LightClientHeaderContainer_HeaderAltair{ + HeaderAltair: ðpbv2.LightClientHeader{ + Beacon: ðpbv1.BeaconBlockHeader{ + Slot: slot.Sub(1), + ProposerIndex: 1, + ParentRoot: []byte{1, 1, 1}, + StateRoot: []byte{1, 1, 1}, + BodyRoot: []byte{1, 1, 1}, + }, + }, + }, + }, + NextSyncCommittee: ðpbv2.SyncCommittee{ + Pubkeys: nil, + AggregatePubkey: nil, + }, + NextSyncCommitteeBranch: nil, + FinalizedHeader: nil, + FinalityBranch: nil, + SyncAggregate: ðpbv1.SyncAggregate{ + SyncCommitteeBits: []byte{1, 1, 1}, + SyncCommitteeSignature: []byte{1, 1, 1}, + }, + SignatureSlot: 7, } - signedBlock, err := blocks.NewSignedBeaconBlock(block) - require.NoError(t, err) - - h, err := signedBlock.Header() - require.NoError(t, err) - - err = st.SetLatestBlockHeader(h.Header) - require.NoError(t, err) - stateRoot, err := st.HashTreeRoot(ctx) - require.NoError(t, err) - - // get a new signed block so the root is updated with the new state root - block.Block.StateRoot = stateRoot[:] - signedBlock, err = blocks.NewSignedBeaconBlock(block) - require.NoError(t, err) - - root, err := block.Block.HashTreeRoot() + err = db.SaveLightClientUpdate(ctx, updatePeriod, ðpbv2.LightClientUpdateWithVersion{ + Version: version.Altair, + Data: update, + }) require.NoError(t, err) mockBlocker := &testutil.MockBlocker{ @@ -841,10 +352,10 @@ func TestLightClientHandler_GetLightClientUpdatesByRange_TooBigInputCountDeneb(t }}, Blocker: mockBlocker, HeadFetcher: mockChainService, + BeaconDB: db, } startPeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) - count := 129 // config.MaxRequestLightClientUpdates is 128 - url := fmt.Sprintf("http://foo.com/?count=%d&start_period=%d", count, startPeriod) + url := fmt.Sprintf("http://foo.com/?count=1&start_period=%d", startPeriod) request := httptest.NewRequest("GET", url, nil) writer := httptest.NewRecorder() writer.Body = &bytes.Buffer{} @@ -855,28 +366,26 @@ func TestLightClientHandler_GetLightClientUpdatesByRange_TooBigInputCountDeneb(t var resp structs.LightClientUpdatesByRangeResponse err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) require.NoError(t, err) - var respHeader structs.LightClientHeaderDeneb - err = json.Unmarshal(resp.Updates[0].Data.AttestedHeader, &respHeader) + require.Equal(t, 1, len(resp.Updates)) require.NoError(t, err) - require.Equal(t, 1, len(resp.Updates)) // Even with big count input, the response is still the max available period, which is 1 in test case. - require.Equal(t, "deneb", resp.Updates[0].Version) - require.Equal(t, hexutil.Encode(attestedHeader.BodyRoot), respHeader.Beacon.BodyRoot) - require.NotNil(t, resp) + require.Equal(t, "altair", resp.Updates[0].Version) + updateJson, err := structs.LightClientUpdateFromConsensus(update) + require.NoError(t, err) + require.DeepEqual(t, updateJson, resp.Updates[0].Data) } -// TODO - check for not having any blocks from the min period, and startPeriod being too early -func TestLightClientHandler_GetLightClientUpdatesByRange_TooEarlyPeriodAltair(t *testing.T) { +func TestLightClientHandler_GetLightClientUpdatesByRangeCapella(t *testing.T) { helpers.ClearCache() ctx := context.Background() config := params.BeaconConfig() - slot := primitives.Slot(config.AltairForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) + slot := primitives.Slot(config.CapellaForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) - attestedState, err := util.NewBeaconStateAltair() + attestedState, err := util.NewBeaconStateCapella() require.NoError(t, err) err = attestedState.SetSlot(slot.Sub(1)) require.NoError(t, err) - parent := util.NewBeaconBlockAltair() + parent := util.NewBeaconBlockCapella() parent.Block.Slot = slot.Sub(1) signedParent, err := blocks.NewSignedBeaconBlock(parent) @@ -896,7 +405,7 @@ func TestLightClientHandler_GetLightClientUpdatesByRange_TooEarlyPeriodAltair(t signedParent, err = blocks.NewSignedBeaconBlock(parent) require.NoError(t, err) - st, err := util.NewBeaconStateAltair() + st, err := util.NewBeaconStateCapella() require.NoError(t, err) err = st.SetSlot(slot) require.NoError(t, err) @@ -904,7 +413,7 @@ func TestLightClientHandler_GetLightClientUpdatesByRange_TooEarlyPeriodAltair(t parentRoot, err := signedParent.Block().HashTreeRoot() require.NoError(t, err) - block := util.NewBeaconBlockAltair() + block := util.NewBeaconBlockCapella() block.Block.Slot = slot block.Block.ParentRoot = parentRoot[:] @@ -931,113 +440,48 @@ func TestLightClientHandler_GetLightClientUpdatesByRange_TooEarlyPeriodAltair(t root, err := block.Block.HashTreeRoot() require.NoError(t, err) - mockBlocker := &testutil.MockBlocker{ - RootBlockMap: map[[32]byte]interfaces.ReadOnlySignedBeaconBlock{ - parentRoot: signedParent, - root: signedBlock, + update := ðpbv2.LightClientUpdate{ + AttestedHeader: ðpbv2.LightClientHeaderContainer{ + Header: ðpbv2.LightClientHeaderContainer_HeaderCapella{ + HeaderCapella: ðpbv2.LightClientHeaderCapella{ + Beacon: ðpbv1.BeaconBlockHeader{ + Slot: 1, + ProposerIndex: 1, + ParentRoot: []byte{1, 1, 1}, + StateRoot: []byte{1, 1, 1}, + BodyRoot: []byte{1, 1, 1}, + }, + Execution: &enginev1.ExecutionPayloadHeaderCapella{ + FeeRecipient: []byte{1, 2, 3}, + }, + ExecutionBranch: [][]byte{{1, 2, 3}, {4, 5, 6}}, + }, + }, }, - SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{ - slot.Sub(1): signedParent, - slot: signedBlock, + NextSyncCommittee: ðpbv2.SyncCommittee{ + Pubkeys: nil, + AggregatePubkey: nil, }, + NextSyncCommitteeBranch: nil, + FinalizedHeader: ðpbv2.LightClientHeaderContainer{ + Header: ðpbv2.LightClientHeaderContainer_HeaderCapella{ + HeaderCapella: ðpbv2.LightClientHeaderCapella{ + Beacon: ðpbv1.BeaconBlockHeader{ + Slot: 1, + ProposerIndex: 1, + ParentRoot: []byte{1, 1, 1}, + StateRoot: []byte{1, 1, 1}, + BodyRoot: []byte{1, 1, 1}, + }, + Execution: nil, + ExecutionBranch: nil, + }, + }, + }, + FinalityBranch: nil, + SyncAggregate: nil, + SignatureSlot: 7, } - mockChainService := &mock.ChainService{Optimistic: true, Slot: &slot, State: st} - s := &Server{ - Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{ - slot.Sub(1): attestedState, - slot: st, - }}, - Blocker: mockBlocker, - HeadFetcher: mockChainService, - } - startPeriod := 1 // very early period before Altair fork - count := 1 - url := fmt.Sprintf("http://foo.com/?count=%d&start_period=%d", count, startPeriod) - request := httptest.NewRequest("GET", url, nil) - writer := httptest.NewRecorder() - writer.Body = &bytes.Buffer{} - - s.GetLightClientUpdatesByRange(writer, request) - - require.Equal(t, http.StatusOK, writer.Code) - var resp structs.LightClientUpdatesByRangeResponse - err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) - require.NoError(t, err) - var respHeader structs.LightClientHeader - err = json.Unmarshal(resp.Updates[0].Data.AttestedHeader, &respHeader) - require.NoError(t, err) - require.Equal(t, 1, len(resp.Updates)) - require.Equal(t, "altair", resp.Updates[0].Version) - require.Equal(t, hexutil.Encode(attestedHeader.BodyRoot), respHeader.Beacon.BodyRoot) - require.NotNil(t, resp) -} - -// TODO - same as above -func TestLightClientHandler_GetLightClientUpdatesByRange_TooBigCountAltair(t *testing.T) { - helpers.ClearCache() - ctx := context.Background() - config := params.BeaconConfig() - slot := primitives.Slot(config.AltairForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) - - attestedState, err := util.NewBeaconStateAltair() - require.NoError(t, err) - err = attestedState.SetSlot(slot.Sub(1)) - require.NoError(t, err) - - parent := util.NewBeaconBlockAltair() - parent.Block.Slot = slot.Sub(1) - - signedParent, err := blocks.NewSignedBeaconBlock(parent) - require.NoError(t, err) - - parentHeader, err := signedParent.Header() - require.NoError(t, err) - attestedHeader := parentHeader.Header - - err = attestedState.SetLatestBlockHeader(attestedHeader) - require.NoError(t, err) - attestedStateRoot, err := attestedState.HashTreeRoot(ctx) - require.NoError(t, err) - - // get a new signed block so the root is updated with the new state root - parent.Block.StateRoot = attestedStateRoot[:] - signedParent, err = blocks.NewSignedBeaconBlock(parent) - require.NoError(t, err) - - st, err := util.NewBeaconStateAltair() - require.NoError(t, err) - err = st.SetSlot(slot) - require.NoError(t, err) - - parentRoot, err := signedParent.Block().HashTreeRoot() - require.NoError(t, err) - - block := util.NewBeaconBlockAltair() - block.Block.Slot = slot - block.Block.ParentRoot = parentRoot[:] - - for i := uint64(0); i < config.SyncCommitteeSize; i++ { - block.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true) - } - - signedBlock, err := blocks.NewSignedBeaconBlock(block) - require.NoError(t, err) - - h, err := signedBlock.Header() - require.NoError(t, err) - - err = st.SetLatestBlockHeader(h.Header) - require.NoError(t, err) - stateRoot, err := st.HashTreeRoot(ctx) - require.NoError(t, err) - - // get a new signed block so the root is updated with the new state root - block.Block.StateRoot = stateRoot[:] - signedBlock, err = blocks.NewSignedBeaconBlock(block) - require.NoError(t, err) - - root, err := block.Block.HashTreeRoot() - require.NoError(t, err) mockBlocker := &testutil.MockBlocker{ RootBlockMap: map[[32]byte]interfaces.ReadOnlySignedBeaconBlock{ @@ -1058,9 +502,8 @@ func TestLightClientHandler_GetLightClientUpdatesByRange_TooBigCountAltair(t *te Blocker: mockBlocker, HeadFetcher: mockChainService, } - startPeriod := 1 // very early period before Altair fork - count := 10 // This is big count as we only have one period in test case. - url := fmt.Sprintf("http://foo.com/?count=%d&start_period=%d", count, startPeriod) + startPeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) + url := fmt.Sprintf("http://foo.com/?count=1&start_period=%d", startPeriod) request := httptest.NewRequest("GET", url, nil) writer := httptest.NewRecorder() writer.Body = &bytes.Buffer{} @@ -1071,111 +514,754 @@ func TestLightClientHandler_GetLightClientUpdatesByRange_TooBigCountAltair(t *te var resp structs.LightClientUpdatesByRangeResponse err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) require.NoError(t, err) - var respHeader structs.LightClientHeader + var respHeader structs.LightClientHeaderCapella err = json.Unmarshal(resp.Updates[0].Data.AttestedHeader, &respHeader) require.NoError(t, err) require.Equal(t, 1, len(resp.Updates)) - require.Equal(t, "altair", resp.Updates[0].Version) + require.Equal(t, "capella", resp.Updates[0].Version) require.Equal(t, hexutil.Encode(attestedHeader.BodyRoot), respHeader.Beacon.BodyRoot) require.NotNil(t, resp) } -func TestLightClientHandler_GetLightClientUpdatesByRange_BeforeAltair(t *testing.T) { - helpers.ClearCache() - ctx := context.Background() - config := params.BeaconConfig() - slot := primitives.Slot(config.AltairForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Sub(1) - - attestedState, err := util.NewBeaconStateCapella() - require.NoError(t, err) - err = attestedState.SetSlot(slot.Sub(1)) - require.NoError(t, err) - - parent := util.NewBeaconBlockCapella() - parent.Block.Slot = slot.Sub(1) - - signedParent, err := blocks.NewSignedBeaconBlock(parent) - require.NoError(t, err) - - parentHeader, err := signedParent.Header() - require.NoError(t, err) - attestedHeader := parentHeader.Header - - err = attestedState.SetLatestBlockHeader(attestedHeader) - require.NoError(t, err) - attestedStateRoot, err := attestedState.HashTreeRoot(ctx) - require.NoError(t, err) - - // get a new signed block so the root is updated with the new state root - parent.Block.StateRoot = attestedStateRoot[:] - signedParent, err = blocks.NewSignedBeaconBlock(parent) - require.NoError(t, err) - - st, err := util.NewBeaconStateCapella() - require.NoError(t, err) - err = st.SetSlot(slot) - require.NoError(t, err) - - parentRoot, err := signedParent.Block().HashTreeRoot() - require.NoError(t, err) - - block := util.NewBeaconBlockCapella() - block.Block.Slot = slot - block.Block.ParentRoot = parentRoot[:] - - for i := uint64(0); i < config.SyncCommitteeSize; i++ { - block.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true) - } - - signedBlock, err := blocks.NewSignedBeaconBlock(block) - require.NoError(t, err) - - h, err := signedBlock.Header() - require.NoError(t, err) - - err = st.SetLatestBlockHeader(h.Header) - require.NoError(t, err) - stateRoot, err := st.HashTreeRoot(ctx) - require.NoError(t, err) - - // get a new signed block so the root is updated with the new state root - block.Block.StateRoot = stateRoot[:] - signedBlock, err = blocks.NewSignedBeaconBlock(block) - require.NoError(t, err) - - root, err := block.Block.HashTreeRoot() - require.NoError(t, err) - - mockBlocker := &testutil.MockBlocker{ - RootBlockMap: map[[32]byte]interfaces.ReadOnlySignedBeaconBlock{ - parentRoot: signedParent, - root: signedBlock, - }, - SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{ - slot.Sub(1): signedParent, - slot: signedBlock, - }, - } - mockChainService := &mock.ChainService{Optimistic: true, Slot: &slot, State: st} - s := &Server{ - Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{ - slot.Sub(1): attestedState, - slot: st, - }}, - Blocker: mockBlocker, - HeadFetcher: mockChainService, - } - startPeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) - count := 1 - url := fmt.Sprintf("http://foo.com/?count=%d&start_period=%d", count, startPeriod) - request := httptest.NewRequest("GET", url, nil) - writer := httptest.NewRecorder() - writer.Body = &bytes.Buffer{} - - s.GetLightClientUpdatesByRange(writer, request) - - require.Equal(t, http.StatusNotFound, writer.Code) -} +//func TestLightClientHandler_GetLightClientUpdatesByRangeDeneb(t *testing.T) { +// helpers.ClearCache() +// ctx := context.Background() +// config := params.BeaconConfig() +// slot := primitives.Slot(config.DenebForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) +// +// attestedState, err := util.NewBeaconStateDeneb() +// require.NoError(t, err) +// err = attestedState.SetSlot(slot.Sub(1)) +// require.NoError(t, err) +// +// parent := util.NewBeaconBlockDeneb() +// parent.Block.Slot = slot.Sub(1) +// +// signedParent, err := blocks.NewSignedBeaconBlock(parent) +// require.NoError(t, err) +// +// parentHeader, err := signedParent.Header() +// require.NoError(t, err) +// attestedHeader := parentHeader.Header +// +// err = attestedState.SetLatestBlockHeader(attestedHeader) +// require.NoError(t, err) +// attestedStateRoot, err := attestedState.HashTreeRoot(ctx) +// require.NoError(t, err) +// +// // get a new signed block so the root is updated with the new state root +// parent.Block.StateRoot = attestedStateRoot[:] +// signedParent, err = blocks.NewSignedBeaconBlock(parent) +// require.NoError(t, err) +// +// st, err := util.NewBeaconStateDeneb() +// require.NoError(t, err) +// err = st.SetSlot(slot) +// require.NoError(t, err) +// +// parentRoot, err := signedParent.Block().HashTreeRoot() +// require.NoError(t, err) +// +// block := util.NewBeaconBlockDeneb() +// block.Block.Slot = slot +// block.Block.ParentRoot = parentRoot[:] +// +// for i := uint64(0); i < config.SyncCommitteeSize; i++ { +// block.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true) +// } +// +// signedBlock, err := blocks.NewSignedBeaconBlock(block) +// require.NoError(t, err) +// +// h, err := signedBlock.Header() +// require.NoError(t, err) +// +// err = st.SetLatestBlockHeader(h.Header) +// require.NoError(t, err) +// stateRoot, err := st.HashTreeRoot(ctx) +// require.NoError(t, err) +// +// // get a new signed block so the root is updated with the new state root +// block.Block.StateRoot = stateRoot[:] +// signedBlock, err = blocks.NewSignedBeaconBlock(block) +// require.NoError(t, err) +// +// root, err := block.Block.HashTreeRoot() +// require.NoError(t, err) +// +// mockBlocker := &testutil.MockBlocker{ +// RootBlockMap: map[[32]byte]interfaces.ReadOnlySignedBeaconBlock{ +// parentRoot: signedParent, +// root: signedBlock, +// }, +// SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{ +// slot.Sub(1): signedParent, +// slot: signedBlock, +// }, +// } +// mockChainService := &mock.ChainService{Optimistic: true, Slot: &slot, State: st} +// s := &Server{ +// Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{ +// slot.Sub(1): attestedState, +// slot: st, +// }}, +// Blocker: mockBlocker, +// HeadFetcher: mockChainService, +// } +// startPeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) +// url := fmt.Sprintf("http://foo.com/?count=1&start_period=%d", startPeriod) +// request := httptest.NewRequest("GET", url, nil) +// writer := httptest.NewRecorder() +// writer.Body = &bytes.Buffer{} +// +// s.GetLightClientUpdatesByRange(writer, request) +// +// require.Equal(t, http.StatusOK, writer.Code) +// var resp structs.LightClientUpdatesByRangeResponse +// err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) +// require.NoError(t, err) +// var respHeader structs.LightClientHeaderDeneb +// err = json.Unmarshal(resp.Updates[0].Data.AttestedHeader, &respHeader) +// require.NoError(t, err) +// require.Equal(t, 1, len(resp.Updates)) +// require.Equal(t, "deneb", resp.Updates[0].Version) +// require.Equal(t, hexutil.Encode(attestedHeader.BodyRoot), respHeader.Beacon.BodyRoot) +// require.NotNil(t, resp) +//} +// +//func TestLightClientHandler_GetLightClientUpdatesByRange_TooBigInputCountAltair(t *testing.T) { +// helpers.ClearCache() +// ctx := context.Background() +// config := params.BeaconConfig() +// slot := primitives.Slot(config.AltairForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) +// +// attestedState, err := util.NewBeaconStateAltair() +// require.NoError(t, err) +// err = attestedState.SetSlot(slot.Sub(1)) +// require.NoError(t, err) +// +// parent := util.NewBeaconBlockAltair() +// parent.Block.Slot = slot.Sub(1) +// +// signedParent, err := blocks.NewSignedBeaconBlock(parent) +// require.NoError(t, err) +// +// parentHeader, err := signedParent.Header() +// require.NoError(t, err) +// attestedHeader := parentHeader.Header +// +// err = attestedState.SetLatestBlockHeader(attestedHeader) +// require.NoError(t, err) +// attestedStateRoot, err := attestedState.HashTreeRoot(ctx) +// require.NoError(t, err) +// +// // get a new signed block so the root is updated with the new state root +// parent.Block.StateRoot = attestedStateRoot[:] +// signedParent, err = blocks.NewSignedBeaconBlock(parent) +// require.NoError(t, err) +// +// st, err := util.NewBeaconStateAltair() +// require.NoError(t, err) +// err = st.SetSlot(slot) +// require.NoError(t, err) +// +// parentRoot, err := signedParent.Block().HashTreeRoot() +// require.NoError(t, err) +// +// block := util.NewBeaconBlockAltair() +// block.Block.Slot = slot +// block.Block.ParentRoot = parentRoot[:] +// +// for i := uint64(0); i < config.SyncCommitteeSize; i++ { +// block.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true) +// } +// +// signedBlock, err := blocks.NewSignedBeaconBlock(block) +// require.NoError(t, err) +// +// h, err := signedBlock.Header() +// require.NoError(t, err) +// +// err = st.SetLatestBlockHeader(h.Header) +// require.NoError(t, err) +// stateRoot, err := st.HashTreeRoot(ctx) +// require.NoError(t, err) +// +// // get a new signed block so the root is updated with the new state root +// block.Block.StateRoot = stateRoot[:] +// signedBlock, err = blocks.NewSignedBeaconBlock(block) +// require.NoError(t, err) +// +// root, err := block.Block.HashTreeRoot() +// require.NoError(t, err) +// +// mockBlocker := &testutil.MockBlocker{ +// RootBlockMap: map[[32]byte]interfaces.ReadOnlySignedBeaconBlock{ +// parentRoot: signedParent, +// root: signedBlock, +// }, +// SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{ +// slot.Sub(1): signedParent, +// slot: signedBlock, +// }, +// } +// mockChainService := &mock.ChainService{Optimistic: true, Slot: &slot, State: st} +// s := &Server{ +// Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{ +// slot.Sub(1): attestedState, +// slot: st, +// }}, +// Blocker: mockBlocker, +// HeadFetcher: mockChainService, +// } +// startPeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) +// count := 129 // config.MaxRequestLightClientUpdates is 128 +// url := fmt.Sprintf("http://foo.com/?count=%d&start_period=%d", count, startPeriod) +// request := httptest.NewRequest("GET", url, nil) +// writer := httptest.NewRecorder() +// writer.Body = &bytes.Buffer{} +// +// s.GetLightClientUpdatesByRange(writer, request) +// +// require.Equal(t, http.StatusOK, writer.Code) +// var resp structs.LightClientUpdatesByRangeResponse +// err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) +// require.NoError(t, err) +// var respHeader structs.LightClientHeader +// err = json.Unmarshal(resp.Updates[0].Data.AttestedHeader, &respHeader) +// require.NoError(t, err) +// require.Equal(t, 1, len(resp.Updates)) // Even with big count input, the response is still the max available period, which is 1 in test case. +// require.Equal(t, "altair", resp.Updates[0].Version) +// require.Equal(t, hexutil.Encode(attestedHeader.BodyRoot), respHeader.Beacon.BodyRoot) +// require.NotNil(t, resp) +//} +// +//func TestLightClientHandler_GetLightClientUpdatesByRange_TooBigInputCountCapella(t *testing.T) { +// helpers.ClearCache() +// ctx := context.Background() +// config := params.BeaconConfig() +// slot := primitives.Slot(config.CapellaForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) +// +// attestedState, err := util.NewBeaconStateCapella() +// require.NoError(t, err) +// err = attestedState.SetSlot(slot.Sub(1)) +// require.NoError(t, err) +// +// parent := util.NewBeaconBlockCapella() +// parent.Block.Slot = slot.Sub(1) +// +// signedParent, err := blocks.NewSignedBeaconBlock(parent) +// require.NoError(t, err) +// +// parentHeader, err := signedParent.Header() +// require.NoError(t, err) +// attestedHeader := parentHeader.Header +// +// err = attestedState.SetLatestBlockHeader(attestedHeader) +// require.NoError(t, err) +// attestedStateRoot, err := attestedState.HashTreeRoot(ctx) +// require.NoError(t, err) +// +// // get a new signed block so the root is updated with the new state root +// parent.Block.StateRoot = attestedStateRoot[:] +// signedParent, err = blocks.NewSignedBeaconBlock(parent) +// require.NoError(t, err) +// +// st, err := util.NewBeaconStateCapella() +// require.NoError(t, err) +// err = st.SetSlot(slot) +// require.NoError(t, err) +// +// parentRoot, err := signedParent.Block().HashTreeRoot() +// require.NoError(t, err) +// +// block := util.NewBeaconBlockCapella() +// block.Block.Slot = slot +// block.Block.ParentRoot = parentRoot[:] +// +// for i := uint64(0); i < config.SyncCommitteeSize; i++ { +// block.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true) +// } +// +// signedBlock, err := blocks.NewSignedBeaconBlock(block) +// require.NoError(t, err) +// +// h, err := signedBlock.Header() +// require.NoError(t, err) +// +// err = st.SetLatestBlockHeader(h.Header) +// require.NoError(t, err) +// stateRoot, err := st.HashTreeRoot(ctx) +// require.NoError(t, err) +// +// // get a new signed block so the root is updated with the new state root +// block.Block.StateRoot = stateRoot[:] +// signedBlock, err = blocks.NewSignedBeaconBlock(block) +// require.NoError(t, err) +// +// root, err := block.Block.HashTreeRoot() +// require.NoError(t, err) +// +// mockBlocker := &testutil.MockBlocker{ +// RootBlockMap: map[[32]byte]interfaces.ReadOnlySignedBeaconBlock{ +// parentRoot: signedParent, +// root: signedBlock, +// }, +// SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{ +// slot.Sub(1): signedParent, +// slot: signedBlock, +// }, +// } +// mockChainService := &mock.ChainService{Optimistic: true, Slot: &slot, State: st} +// s := &Server{ +// Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{ +// slot.Sub(1): attestedState, +// slot: st, +// }}, +// Blocker: mockBlocker, +// HeadFetcher: mockChainService, +// } +// startPeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) +// count := 129 // config.MaxRequestLightClientUpdates is 128 +// url := fmt.Sprintf("http://foo.com/?count=%d&start_period=%d", count, startPeriod) +// request := httptest.NewRequest("GET", url, nil) +// writer := httptest.NewRecorder() +// writer.Body = &bytes.Buffer{} +// +// s.GetLightClientUpdatesByRange(writer, request) +// +// require.Equal(t, http.StatusOK, writer.Code) +// var resp structs.LightClientUpdatesByRangeResponse +// err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) +// require.NoError(t, err) +// var respHeader structs.LightClientHeaderCapella +// err = json.Unmarshal(resp.Updates[0].Data.AttestedHeader, &respHeader) +// require.NoError(t, err) +// require.Equal(t, 1, len(resp.Updates)) // Even with big count input, the response is still the max available period, which is 1 in test case. +// require.Equal(t, "capella", resp.Updates[0].Version) +// require.Equal(t, hexutil.Encode(attestedHeader.BodyRoot), respHeader.Beacon.BodyRoot) +// require.NotNil(t, resp) +//} +// +//func TestLightClientHandler_GetLightClientUpdatesByRange_TooBigInputCountDeneb(t *testing.T) { +// helpers.ClearCache() +// ctx := context.Background() +// config := params.BeaconConfig() +// slot := primitives.Slot(config.DenebForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) +// +// attestedState, err := util.NewBeaconStateDeneb() +// require.NoError(t, err) +// err = attestedState.SetSlot(slot.Sub(1)) +// require.NoError(t, err) +// +// parent := util.NewBeaconBlockDeneb() +// parent.Block.Slot = slot.Sub(1) +// +// signedParent, err := blocks.NewSignedBeaconBlock(parent) +// require.NoError(t, err) +// +// parentHeader, err := signedParent.Header() +// require.NoError(t, err) +// attestedHeader := parentHeader.Header +// +// err = attestedState.SetLatestBlockHeader(attestedHeader) +// require.NoError(t, err) +// attestedStateRoot, err := attestedState.HashTreeRoot(ctx) +// require.NoError(t, err) +// +// // get a new signed block so the root is updated with the new state root +// parent.Block.StateRoot = attestedStateRoot[:] +// signedParent, err = blocks.NewSignedBeaconBlock(parent) +// require.NoError(t, err) +// +// st, err := util.NewBeaconStateDeneb() +// require.NoError(t, err) +// err = st.SetSlot(slot) +// require.NoError(t, err) +// +// parentRoot, err := signedParent.Block().HashTreeRoot() +// require.NoError(t, err) +// +// block := util.NewBeaconBlockDeneb() +// block.Block.Slot = slot +// block.Block.ParentRoot = parentRoot[:] +// +// for i := uint64(0); i < config.SyncCommitteeSize; i++ { +// block.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true) +// } +// +// signedBlock, err := blocks.NewSignedBeaconBlock(block) +// require.NoError(t, err) +// +// h, err := signedBlock.Header() +// require.NoError(t, err) +// +// err = st.SetLatestBlockHeader(h.Header) +// require.NoError(t, err) +// stateRoot, err := st.HashTreeRoot(ctx) +// require.NoError(t, err) +// +// // get a new signed block so the root is updated with the new state root +// block.Block.StateRoot = stateRoot[:] +// signedBlock, err = blocks.NewSignedBeaconBlock(block) +// require.NoError(t, err) +// +// root, err := block.Block.HashTreeRoot() +// require.NoError(t, err) +// +// mockBlocker := &testutil.MockBlocker{ +// RootBlockMap: map[[32]byte]interfaces.ReadOnlySignedBeaconBlock{ +// parentRoot: signedParent, +// root: signedBlock, +// }, +// SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{ +// slot.Sub(1): signedParent, +// slot: signedBlock, +// }, +// } +// mockChainService := &mock.ChainService{Optimistic: true, Slot: &slot, State: st} +// s := &Server{ +// Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{ +// slot.Sub(1): attestedState, +// slot: st, +// }}, +// Blocker: mockBlocker, +// HeadFetcher: mockChainService, +// } +// startPeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) +// count := 129 // config.MaxRequestLightClientUpdates is 128 +// url := fmt.Sprintf("http://foo.com/?count=%d&start_period=%d", count, startPeriod) +// request := httptest.NewRequest("GET", url, nil) +// writer := httptest.NewRecorder() +// writer.Body = &bytes.Buffer{} +// +// s.GetLightClientUpdatesByRange(writer, request) +// +// require.Equal(t, http.StatusOK, writer.Code) +// var resp structs.LightClientUpdatesByRangeResponse +// err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) +// require.NoError(t, err) +// var respHeader structs.LightClientHeaderDeneb +// err = json.Unmarshal(resp.Updates[0].Data.AttestedHeader, &respHeader) +// require.NoError(t, err) +// require.Equal(t, 1, len(resp.Updates)) // Even with big count input, the response is still the max available period, which is 1 in test case. +// require.Equal(t, "deneb", resp.Updates[0].Version) +// require.Equal(t, hexutil.Encode(attestedHeader.BodyRoot), respHeader.Beacon.BodyRoot) +// require.NotNil(t, resp) +//} +// +//// TODO - check for not having any blocks from the min period, and startPeriod being too early +//func TestLightClientHandler_GetLightClientUpdatesByRange_TooEarlyPeriodAltair(t *testing.T) { +// helpers.ClearCache() +// ctx := context.Background() +// config := params.BeaconConfig() +// slot := primitives.Slot(config.AltairForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) +// +// attestedState, err := util.NewBeaconStateAltair() +// require.NoError(t, err) +// err = attestedState.SetSlot(slot.Sub(1)) +// require.NoError(t, err) +// +// parent := util.NewBeaconBlockAltair() +// parent.Block.Slot = slot.Sub(1) +// +// signedParent, err := blocks.NewSignedBeaconBlock(parent) +// require.NoError(t, err) +// +// parentHeader, err := signedParent.Header() +// require.NoError(t, err) +// attestedHeader := parentHeader.Header +// +// err = attestedState.SetLatestBlockHeader(attestedHeader) +// require.NoError(t, err) +// attestedStateRoot, err := attestedState.HashTreeRoot(ctx) +// require.NoError(t, err) +// +// // get a new signed block so the root is updated with the new state root +// parent.Block.StateRoot = attestedStateRoot[:] +// signedParent, err = blocks.NewSignedBeaconBlock(parent) +// require.NoError(t, err) +// +// st, err := util.NewBeaconStateAltair() +// require.NoError(t, err) +// err = st.SetSlot(slot) +// require.NoError(t, err) +// +// parentRoot, err := signedParent.Block().HashTreeRoot() +// require.NoError(t, err) +// +// block := util.NewBeaconBlockAltair() +// block.Block.Slot = slot +// block.Block.ParentRoot = parentRoot[:] +// +// for i := uint64(0); i < config.SyncCommitteeSize; i++ { +// block.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true) +// } +// +// signedBlock, err := blocks.NewSignedBeaconBlock(block) +// require.NoError(t, err) +// +// h, err := signedBlock.Header() +// require.NoError(t, err) +// +// err = st.SetLatestBlockHeader(h.Header) +// require.NoError(t, err) +// stateRoot, err := st.HashTreeRoot(ctx) +// require.NoError(t, err) +// +// // get a new signed block so the root is updated with the new state root +// block.Block.StateRoot = stateRoot[:] +// signedBlock, err = blocks.NewSignedBeaconBlock(block) +// require.NoError(t, err) +// +// root, err := block.Block.HashTreeRoot() +// require.NoError(t, err) +// +// mockBlocker := &testutil.MockBlocker{ +// RootBlockMap: map[[32]byte]interfaces.ReadOnlySignedBeaconBlock{ +// parentRoot: signedParent, +// root: signedBlock, +// }, +// SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{ +// slot.Sub(1): signedParent, +// slot: signedBlock, +// }, +// } +// mockChainService := &mock.ChainService{Optimistic: true, Slot: &slot, State: st} +// s := &Server{ +// Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{ +// slot.Sub(1): attestedState, +// slot: st, +// }}, +// Blocker: mockBlocker, +// HeadFetcher: mockChainService, +// } +// startPeriod := 1 // very early period before Altair fork +// count := 1 +// url := fmt.Sprintf("http://foo.com/?count=%d&start_period=%d", count, startPeriod) +// request := httptest.NewRequest("GET", url, nil) +// writer := httptest.NewRecorder() +// writer.Body = &bytes.Buffer{} +// +// s.GetLightClientUpdatesByRange(writer, request) +// +// require.Equal(t, http.StatusOK, writer.Code) +// var resp structs.LightClientUpdatesByRangeResponse +// err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) +// require.NoError(t, err) +// var respHeader structs.LightClientHeader +// err = json.Unmarshal(resp.Updates[0].Data.AttestedHeader, &respHeader) +// require.NoError(t, err) +// require.Equal(t, 1, len(resp.Updates)) +// require.Equal(t, "altair", resp.Updates[0].Version) +// require.Equal(t, hexutil.Encode(attestedHeader.BodyRoot), respHeader.Beacon.BodyRoot) +// require.NotNil(t, resp) +//} +// +//// TODO - same as above +//func TestLightClientHandler_GetLightClientUpdatesByRange_TooBigCountAltair(t *testing.T) { +// helpers.ClearCache() +// ctx := context.Background() +// config := params.BeaconConfig() +// slot := primitives.Slot(config.AltairForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) +// +// attestedState, err := util.NewBeaconStateAltair() +// require.NoError(t, err) +// err = attestedState.SetSlot(slot.Sub(1)) +// require.NoError(t, err) +// +// parent := util.NewBeaconBlockAltair() +// parent.Block.Slot = slot.Sub(1) +// +// signedParent, err := blocks.NewSignedBeaconBlock(parent) +// require.NoError(t, err) +// +// parentHeader, err := signedParent.Header() +// require.NoError(t, err) +// attestedHeader := parentHeader.Header +// +// err = attestedState.SetLatestBlockHeader(attestedHeader) +// require.NoError(t, err) +// attestedStateRoot, err := attestedState.HashTreeRoot(ctx) +// require.NoError(t, err) +// +// // get a new signed block so the root is updated with the new state root +// parent.Block.StateRoot = attestedStateRoot[:] +// signedParent, err = blocks.NewSignedBeaconBlock(parent) +// require.NoError(t, err) +// +// st, err := util.NewBeaconStateAltair() +// require.NoError(t, err) +// err = st.SetSlot(slot) +// require.NoError(t, err) +// +// parentRoot, err := signedParent.Block().HashTreeRoot() +// require.NoError(t, err) +// +// block := util.NewBeaconBlockAltair() +// block.Block.Slot = slot +// block.Block.ParentRoot = parentRoot[:] +// +// for i := uint64(0); i < config.SyncCommitteeSize; i++ { +// block.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true) +// } +// +// signedBlock, err := blocks.NewSignedBeaconBlock(block) +// require.NoError(t, err) +// +// h, err := signedBlock.Header() +// require.NoError(t, err) +// +// err = st.SetLatestBlockHeader(h.Header) +// require.NoError(t, err) +// stateRoot, err := st.HashTreeRoot(ctx) +// require.NoError(t, err) +// +// // get a new signed block so the root is updated with the new state root +// block.Block.StateRoot = stateRoot[:] +// signedBlock, err = blocks.NewSignedBeaconBlock(block) +// require.NoError(t, err) +// +// root, err := block.Block.HashTreeRoot() +// require.NoError(t, err) +// +// mockBlocker := &testutil.MockBlocker{ +// RootBlockMap: map[[32]byte]interfaces.ReadOnlySignedBeaconBlock{ +// parentRoot: signedParent, +// root: signedBlock, +// }, +// SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{ +// slot.Sub(1): signedParent, +// slot: signedBlock, +// }, +// } +// mockChainService := &mock.ChainService{Optimistic: true, Slot: &slot, State: st} +// s := &Server{ +// Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{ +// slot.Sub(1): attestedState, +// slot: st, +// }}, +// Blocker: mockBlocker, +// HeadFetcher: mockChainService, +// } +// startPeriod := 1 // very early period before Altair fork +// count := 10 // This is big count as we only have one period in test case. +// url := fmt.Sprintf("http://foo.com/?count=%d&start_period=%d", count, startPeriod) +// request := httptest.NewRequest("GET", url, nil) +// writer := httptest.NewRecorder() +// writer.Body = &bytes.Buffer{} +// +// s.GetLightClientUpdatesByRange(writer, request) +// +// require.Equal(t, http.StatusOK, writer.Code) +// var resp structs.LightClientUpdatesByRangeResponse +// err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) +// require.NoError(t, err) +// var respHeader structs.LightClientHeader +// err = json.Unmarshal(resp.Updates[0].Data.AttestedHeader, &respHeader) +// require.NoError(t, err) +// require.Equal(t, 1, len(resp.Updates)) +// require.Equal(t, "altair", resp.Updates[0].Version) +// require.Equal(t, hexutil.Encode(attestedHeader.BodyRoot), respHeader.Beacon.BodyRoot) +// require.NotNil(t, resp) +//} +// +//func TestLightClientHandler_GetLightClientUpdatesByRange_BeforeAltair(t *testing.T) { +// helpers.ClearCache() +// ctx := context.Background() +// config := params.BeaconConfig() +// slot := primitives.Slot(config.AltairForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Sub(1) +// +// attestedState, err := util.NewBeaconStateCapella() +// require.NoError(t, err) +// err = attestedState.SetSlot(slot.Sub(1)) +// require.NoError(t, err) +// +// parent := util.NewBeaconBlockCapella() +// parent.Block.Slot = slot.Sub(1) +// +// signedParent, err := blocks.NewSignedBeaconBlock(parent) +// require.NoError(t, err) +// +// parentHeader, err := signedParent.Header() +// require.NoError(t, err) +// attestedHeader := parentHeader.Header +// +// err = attestedState.SetLatestBlockHeader(attestedHeader) +// require.NoError(t, err) +// attestedStateRoot, err := attestedState.HashTreeRoot(ctx) +// require.NoError(t, err) +// +// // get a new signed block so the root is updated with the new state root +// parent.Block.StateRoot = attestedStateRoot[:] +// signedParent, err = blocks.NewSignedBeaconBlock(parent) +// require.NoError(t, err) +// +// st, err := util.NewBeaconStateCapella() +// require.NoError(t, err) +// err = st.SetSlot(slot) +// require.NoError(t, err) +// +// parentRoot, err := signedParent.Block().HashTreeRoot() +// require.NoError(t, err) +// +// block := util.NewBeaconBlockCapella() +// block.Block.Slot = slot +// block.Block.ParentRoot = parentRoot[:] +// +// for i := uint64(0); i < config.SyncCommitteeSize; i++ { +// block.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true) +// } +// +// signedBlock, err := blocks.NewSignedBeaconBlock(block) +// require.NoError(t, err) +// +// h, err := signedBlock.Header() +// require.NoError(t, err) +// +// err = st.SetLatestBlockHeader(h.Header) +// require.NoError(t, err) +// stateRoot, err := st.HashTreeRoot(ctx) +// require.NoError(t, err) +// +// // get a new signed block so the root is updated with the new state root +// block.Block.StateRoot = stateRoot[:] +// signedBlock, err = blocks.NewSignedBeaconBlock(block) +// require.NoError(t, err) +// +// root, err := block.Block.HashTreeRoot() +// require.NoError(t, err) +// +// mockBlocker := &testutil.MockBlocker{ +// RootBlockMap: map[[32]byte]interfaces.ReadOnlySignedBeaconBlock{ +// parentRoot: signedParent, +// root: signedBlock, +// }, +// SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{ +// slot.Sub(1): signedParent, +// slot: signedBlock, +// }, +// } +// mockChainService := &mock.ChainService{Optimistic: true, Slot: &slot, State: st} +// s := &Server{ +// Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{ +// slot.Sub(1): attestedState, +// slot: st, +// }}, +// Blocker: mockBlocker, +// HeadFetcher: mockChainService, +// } +// startPeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) +// count := 1 +// url := fmt.Sprintf("http://foo.com/?count=%d&start_period=%d", count, startPeriod) +// request := httptest.NewRequest("GET", url, nil) +// writer := httptest.NewRecorder() +// writer.Body = &bytes.Buffer{} +// +// s.GetLightClientUpdatesByRange(writer, request) +// +// require.Equal(t, http.StatusNotFound, writer.Code) +//} func TestLightClientHandler_GetLightClientFinalityUpdateAltair(t *testing.T) { helpers.ClearCache() @@ -2047,3 +2133,13 @@ func TestLightClientHandler_GetLightClientEventBlock_NeedFetchParent(t *testing. require.Equal(t, true, syncAggregate.SyncCommitteeBits.Count() >= minSignaturesRequired) require.Equal(t, slot-1, eventBlock.Block().Slot()) } + +// setupDB instantiates and returns a Store instance. +func setupDB(t testing.TB) *kv.Store { + db, err := kv.NewKVStore(context.Background(), t.TempDir()) + require.NoError(t, err, "Failed to instantiate DB") + t.Cleanup(func() { + require.NoError(t, db.Close(), "Failed to close database") + }) + return db +} From dedfacb046c31944474ecb64fee50187f8735e64 Mon Sep 17 00:00:00 2001 From: Inspector-Butters Date: Sun, 13 Oct 2024 16:12:49 +0200 Subject: [PATCH 04/12] range forks tests --- .../rpc/eth/light-client/handlers_test.go | 307 +++++++++++------- 1 file changed, 190 insertions(+), 117 deletions(-) diff --git a/beacon-chain/rpc/eth/light-client/handlers_test.go b/beacon-chain/rpc/eth/light-client/handlers_test.go index b32e923c8f68..b124f0c6e880 100644 --- a/beacon-chain/rpc/eth/light-client/handlers_test.go +++ b/beacon-chain/rpc/eth/light-client/handlers_test.go @@ -440,12 +440,16 @@ func TestLightClientHandler_GetLightClientUpdatesByRangeCapella(t *testing.T) { root, err := block.Block.HashTreeRoot() require.NoError(t, err) + db := setupDB(t) + + updatePeriod := uint64(slot.Sub(1).Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch))) + update := ðpbv2.LightClientUpdate{ AttestedHeader: ðpbv2.LightClientHeaderContainer{ Header: ðpbv2.LightClientHeaderContainer_HeaderCapella{ HeaderCapella: ðpbv2.LightClientHeaderCapella{ Beacon: ðpbv1.BeaconBlockHeader{ - Slot: 1, + Slot: slot.Sub(1), ProposerIndex: 1, ParentRoot: []byte{1, 1, 1}, StateRoot: []byte{1, 1, 1}, @@ -467,22 +471,33 @@ func TestLightClientHandler_GetLightClientUpdatesByRangeCapella(t *testing.T) { Header: ðpbv2.LightClientHeaderContainer_HeaderCapella{ HeaderCapella: ðpbv2.LightClientHeaderCapella{ Beacon: ðpbv1.BeaconBlockHeader{ - Slot: 1, + Slot: 12, ProposerIndex: 1, ParentRoot: []byte{1, 1, 1}, StateRoot: []byte{1, 1, 1}, BodyRoot: []byte{1, 1, 1}, }, - Execution: nil, - ExecutionBranch: nil, + Execution: &enginev1.ExecutionPayloadHeaderCapella{ + FeeRecipient: []byte{1, 2, 3}, + }, + ExecutionBranch: [][]byte{{1, 2, 3}, {4, 5, 6}}, }, }, }, FinalityBranch: nil, - SyncAggregate: nil, - SignatureSlot: 7, + SyncAggregate: ðpbv1.SyncAggregate{ + SyncCommitteeBits: []byte{1, 1, 1}, + SyncCommitteeSignature: []byte{1, 1, 1}, + }, + SignatureSlot: 7, } + err = db.SaveLightClientUpdate(ctx, updatePeriod, ðpbv2.LightClientUpdateWithVersion{ + Version: version.Capella, + Data: update, + }) + require.NoError(t, err) + mockBlocker := &testutil.MockBlocker{ RootBlockMap: map[[32]byte]interfaces.ReadOnlySignedBeaconBlock{ parentRoot: signedParent, @@ -501,6 +516,7 @@ func TestLightClientHandler_GetLightClientUpdatesByRangeCapella(t *testing.T) { }}, Blocker: mockBlocker, HeadFetcher: mockChainService, + BeaconDB: db, } startPeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) url := fmt.Sprintf("http://foo.com/?count=1&start_period=%d", startPeriod) @@ -514,121 +530,178 @@ func TestLightClientHandler_GetLightClientUpdatesByRangeCapella(t *testing.T) { var resp structs.LightClientUpdatesByRangeResponse err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) require.NoError(t, err) - var respHeader structs.LightClientHeaderCapella - err = json.Unmarshal(resp.Updates[0].Data.AttestedHeader, &respHeader) - require.NoError(t, err) require.Equal(t, 1, len(resp.Updates)) + require.NoError(t, err) require.Equal(t, "capella", resp.Updates[0].Version) - require.Equal(t, hexutil.Encode(attestedHeader.BodyRoot), respHeader.Beacon.BodyRoot) - require.NotNil(t, resp) + updateJson, err := structs.LightClientUpdateFromConsensus(update) + require.NoError(t, err) + require.DeepEqual(t, updateJson, resp.Updates[0].Data) +} + +func TestLightClientHandler_GetLightClientUpdatesByRangeDeneb(t *testing.T) { + helpers.ClearCache() + ctx := context.Background() + config := params.BeaconConfig() + slot := primitives.Slot(config.DenebForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) + + attestedState, err := util.NewBeaconStateDeneb() + require.NoError(t, err) + err = attestedState.SetSlot(slot.Sub(1)) + require.NoError(t, err) + + parent := util.NewBeaconBlockDeneb() + parent.Block.Slot = slot.Sub(1) + + signedParent, err := blocks.NewSignedBeaconBlock(parent) + require.NoError(t, err) + + parentHeader, err := signedParent.Header() + require.NoError(t, err) + attestedHeader := parentHeader.Header + + err = attestedState.SetLatestBlockHeader(attestedHeader) + require.NoError(t, err) + attestedStateRoot, err := attestedState.HashTreeRoot(ctx) + require.NoError(t, err) + + // get a new signed block so the root is updated with the new state root + parent.Block.StateRoot = attestedStateRoot[:] + signedParent, err = blocks.NewSignedBeaconBlock(parent) + require.NoError(t, err) + + st, err := util.NewBeaconStateDeneb() + require.NoError(t, err) + err = st.SetSlot(slot) + require.NoError(t, err) + + parentRoot, err := signedParent.Block().HashTreeRoot() + require.NoError(t, err) + + block := util.NewBeaconBlockDeneb() + block.Block.Slot = slot + block.Block.ParentRoot = parentRoot[:] + + for i := uint64(0); i < config.SyncCommitteeSize; i++ { + block.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true) + } + + signedBlock, err := blocks.NewSignedBeaconBlock(block) + require.NoError(t, err) + + h, err := signedBlock.Header() + require.NoError(t, err) + + err = st.SetLatestBlockHeader(h.Header) + require.NoError(t, err) + stateRoot, err := st.HashTreeRoot(ctx) + require.NoError(t, err) + + // get a new signed block so the root is updated with the new state root + block.Block.StateRoot = stateRoot[:] + signedBlock, err = blocks.NewSignedBeaconBlock(block) + require.NoError(t, err) + + root, err := block.Block.HashTreeRoot() + require.NoError(t, err) + + db := setupDB(t) + + updatePeriod := uint64(slot.Sub(1).Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch))) + + update := ðpbv2.LightClientUpdate{ + AttestedHeader: ðpbv2.LightClientHeaderContainer{ + Header: ðpbv2.LightClientHeaderContainer_HeaderCapella{ + HeaderCapella: ðpbv2.LightClientHeaderCapella{ + Beacon: ðpbv1.BeaconBlockHeader{ + Slot: slot.Sub(1), + ProposerIndex: 1, + ParentRoot: []byte{1, 1, 1}, + StateRoot: []byte{1, 1, 1}, + BodyRoot: []byte{1, 1, 1}, + }, + Execution: &enginev1.ExecutionPayloadHeaderCapella{ + FeeRecipient: []byte{1, 2, 3}, + }, + ExecutionBranch: [][]byte{{1, 2, 3}, {4, 5, 6}}, + }, + }, + }, + NextSyncCommittee: ðpbv2.SyncCommittee{ + Pubkeys: nil, + AggregatePubkey: nil, + }, + NextSyncCommitteeBranch: nil, + FinalizedHeader: ðpbv2.LightClientHeaderContainer{ + Header: ðpbv2.LightClientHeaderContainer_HeaderDeneb{ + HeaderDeneb: ðpbv2.LightClientHeaderDeneb{ + Beacon: ðpbv1.BeaconBlockHeader{ + Slot: 12, + ProposerIndex: 1, + ParentRoot: []byte{1, 1, 1}, + StateRoot: []byte{1, 1, 1}, + BodyRoot: []byte{1, 1, 1}, + }, + Execution: &enginev1.ExecutionPayloadHeaderDeneb{ + FeeRecipient: []byte{1, 2, 3}, + }, + ExecutionBranch: [][]byte{{1, 2, 3}, {4, 5, 6}}, + }, + }, + }, + FinalityBranch: nil, + SyncAggregate: ðpbv1.SyncAggregate{ + SyncCommitteeBits: []byte{1, 1, 1}, + SyncCommitteeSignature: []byte{1, 1, 1}, + }, + SignatureSlot: 7, + } + + err = db.SaveLightClientUpdate(ctx, updatePeriod, ðpbv2.LightClientUpdateWithVersion{ + Version: version.Deneb, + Data: update, + }) + require.NoError(t, err) + + mockBlocker := &testutil.MockBlocker{ + RootBlockMap: map[[32]byte]interfaces.ReadOnlySignedBeaconBlock{ + parentRoot: signedParent, + root: signedBlock, + }, + SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{ + slot.Sub(1): signedParent, + slot: signedBlock, + }, + } + mockChainService := &mock.ChainService{Optimistic: true, Slot: &slot, State: st} + s := &Server{ + Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{ + slot.Sub(1): attestedState, + slot: st, + }}, + Blocker: mockBlocker, + HeadFetcher: mockChainService, + BeaconDB: db, + } + startPeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) + url := fmt.Sprintf("http://foo.com/?count=1&start_period=%d", startPeriod) + request := httptest.NewRequest("GET", url, nil) + writer := httptest.NewRecorder() + writer.Body = &bytes.Buffer{} + + s.GetLightClientUpdatesByRange(writer, request) + + require.Equal(t, http.StatusOK, writer.Code) + var resp structs.LightClientUpdatesByRangeResponse + err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) + require.NoError(t, err) + require.Equal(t, 1, len(resp.Updates)) + require.NoError(t, err) + require.Equal(t, "deneb", resp.Updates[0].Version) + updateJson, err := structs.LightClientUpdateFromConsensus(update) + require.NoError(t, err) + require.DeepEqual(t, updateJson, resp.Updates[0].Data) } -//func TestLightClientHandler_GetLightClientUpdatesByRangeDeneb(t *testing.T) { -// helpers.ClearCache() -// ctx := context.Background() -// config := params.BeaconConfig() -// slot := primitives.Slot(config.DenebForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) -// -// attestedState, err := util.NewBeaconStateDeneb() -// require.NoError(t, err) -// err = attestedState.SetSlot(slot.Sub(1)) -// require.NoError(t, err) -// -// parent := util.NewBeaconBlockDeneb() -// parent.Block.Slot = slot.Sub(1) -// -// signedParent, err := blocks.NewSignedBeaconBlock(parent) -// require.NoError(t, err) -// -// parentHeader, err := signedParent.Header() -// require.NoError(t, err) -// attestedHeader := parentHeader.Header -// -// err = attestedState.SetLatestBlockHeader(attestedHeader) -// require.NoError(t, err) -// attestedStateRoot, err := attestedState.HashTreeRoot(ctx) -// require.NoError(t, err) -// -// // get a new signed block so the root is updated with the new state root -// parent.Block.StateRoot = attestedStateRoot[:] -// signedParent, err = blocks.NewSignedBeaconBlock(parent) -// require.NoError(t, err) -// -// st, err := util.NewBeaconStateDeneb() -// require.NoError(t, err) -// err = st.SetSlot(slot) -// require.NoError(t, err) -// -// parentRoot, err := signedParent.Block().HashTreeRoot() -// require.NoError(t, err) -// -// block := util.NewBeaconBlockDeneb() -// block.Block.Slot = slot -// block.Block.ParentRoot = parentRoot[:] -// -// for i := uint64(0); i < config.SyncCommitteeSize; i++ { -// block.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true) -// } -// -// signedBlock, err := blocks.NewSignedBeaconBlock(block) -// require.NoError(t, err) -// -// h, err := signedBlock.Header() -// require.NoError(t, err) -// -// err = st.SetLatestBlockHeader(h.Header) -// require.NoError(t, err) -// stateRoot, err := st.HashTreeRoot(ctx) -// require.NoError(t, err) -// -// // get a new signed block so the root is updated with the new state root -// block.Block.StateRoot = stateRoot[:] -// signedBlock, err = blocks.NewSignedBeaconBlock(block) -// require.NoError(t, err) -// -// root, err := block.Block.HashTreeRoot() -// require.NoError(t, err) -// -// mockBlocker := &testutil.MockBlocker{ -// RootBlockMap: map[[32]byte]interfaces.ReadOnlySignedBeaconBlock{ -// parentRoot: signedParent, -// root: signedBlock, -// }, -// SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{ -// slot.Sub(1): signedParent, -// slot: signedBlock, -// }, -// } -// mockChainService := &mock.ChainService{Optimistic: true, Slot: &slot, State: st} -// s := &Server{ -// Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{ -// slot.Sub(1): attestedState, -// slot: st, -// }}, -// Blocker: mockBlocker, -// HeadFetcher: mockChainService, -// } -// startPeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) -// url := fmt.Sprintf("http://foo.com/?count=1&start_period=%d", startPeriod) -// request := httptest.NewRequest("GET", url, nil) -// writer := httptest.NewRecorder() -// writer.Body = &bytes.Buffer{} -// -// s.GetLightClientUpdatesByRange(writer, request) -// -// require.Equal(t, http.StatusOK, writer.Code) -// var resp structs.LightClientUpdatesByRangeResponse -// err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) -// require.NoError(t, err) -// var respHeader structs.LightClientHeaderDeneb -// err = json.Unmarshal(resp.Updates[0].Data.AttestedHeader, &respHeader) -// require.NoError(t, err) -// require.Equal(t, 1, len(resp.Updates)) -// require.Equal(t, "deneb", resp.Updates[0].Version) -// require.Equal(t, hexutil.Encode(attestedHeader.BodyRoot), respHeader.Beacon.BodyRoot) -// require.NotNil(t, resp) -//} -// //func TestLightClientHandler_GetLightClientUpdatesByRange_TooBigInputCountAltair(t *testing.T) { // helpers.ClearCache() // ctx := context.Background() From b1831caf13e5ec111262e9bb470d5142eb9013f6 Mon Sep 17 00:00:00 2001 From: Inspector-Butters Date: Mon, 14 Oct 2024 13:16:31 +0200 Subject: [PATCH 05/12] finish tests --- beacon-chain/rpc/eth/light-client/BUILD.bazel | 3 + beacon-chain/rpc/eth/light-client/handlers.go | 4 +- .../rpc/eth/light-client/handlers_test.go | 1993 ++++++++++------- 3 files changed, 1156 insertions(+), 844 deletions(-) diff --git a/beacon-chain/rpc/eth/light-client/BUILD.bazel b/beacon-chain/rpc/eth/light-client/BUILD.bazel index d21b3b2ebc03..498cce61e0b5 100644 --- a/beacon-chain/rpc/eth/light-client/BUILD.bazel +++ b/beacon-chain/rpc/eth/light-client/BUILD.bazel @@ -45,6 +45,7 @@ go_test( "//beacon-chain/blockchain/testing:go_default_library", "//beacon-chain/core/helpers:go_default_library", "//beacon-chain/core/light-client:go_default_library", + "//beacon-chain/db/kv:go_default_library", "//beacon-chain/rpc/testutil:go_default_library", "//beacon-chain/state:go_default_library", "//config/fieldparams:go_default_library", @@ -52,9 +53,11 @@ go_test( "//consensus-types/blocks:go_default_library", "//consensus-types/interfaces:go_default_library", "//consensus-types/primitives:go_default_library", + "//proto/engine/v1:go_default_library", "//proto/eth/v1:go_default_library", "//proto/eth/v2:go_default_library", "//proto/prysm/v1alpha1:go_default_library", + "//runtime/version:go_default_library", "//testing/assert:go_default_library", "//testing/require:go_default_library", "//testing/util:go_default_library", diff --git a/beacon-chain/rpc/eth/light-client/handlers.go b/beacon-chain/rpc/eth/light-client/handlers.go index 4fcf91eb0189..fc81bcc57010 100644 --- a/beacon-chain/rpc/eth/light-client/handlers.go +++ b/beacon-chain/rpc/eth/light-client/handlers.go @@ -123,6 +123,7 @@ func (s *Server) GetLightClientUpdatesByRange(w http.ResponseWriter, req *http.R } updates := make([]*structs.LightClientUpdateResponse, len(updatesMap)) + updatesCount := 0 for i, j := startPeriod, 0; i <= endPeriod; i, j = i+1, j+1 { update, ok := updatesMap[i] if !ok { @@ -137,9 +138,10 @@ func (s *Server) GetLightClientUpdatesByRange(w http.ResponseWriter, req *http.R } updates[j] = updateResponse + updatesCount++ } - httputil.WriteJson(w, updates) + httputil.WriteJson(w, updates[:updatesCount]) } // GetLightClientFinalityUpdate - implements https://github.com/ethereum/beacon-APIs/blob/263f4ed6c263c967f13279c7a9f5629b51c5fc55/apis/beacon/light_client/finality_update.yaml diff --git a/beacon-chain/rpc/eth/light-client/handlers_test.go b/beacon-chain/rpc/eth/light-client/handlers_test.go index b124f0c6e880..0b23c42c7bfc 100644 --- a/beacon-chain/rpc/eth/light-client/handlers_test.go +++ b/beacon-chain/rpc/eth/light-client/handlers_test.go @@ -230,75 +230,22 @@ func TestLightClientHandler_GetLightClientBootstrap_Electra(t *testing.T) { require.NotNil(t, resp.Data.CurrentSyncCommitteeBranch) } +// GetLightClientByRange tests + func TestLightClientHandler_GetLightClientUpdatesByRangeAltair(t *testing.T) { helpers.ClearCache() ctx := context.Background() config := params.BeaconConfig() slot := primitives.Slot(config.AltairForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) - attestedState, err := util.NewBeaconStateAltair() - require.NoError(t, err) - err = attestedState.SetSlot(slot.Sub(1)) - require.NoError(t, err) - - parent := util.NewBeaconBlockAltair() - parent.Block.Slot = slot.Sub(1) - - signedParent, err := blocks.NewSignedBeaconBlock(parent) - require.NoError(t, err) - - parentHeader, err := signedParent.Header() - require.NoError(t, err) - attestedHeader := parentHeader.Header - - err = attestedState.SetLatestBlockHeader(attestedHeader) - require.NoError(t, err) - attestedStateRoot, err := attestedState.HashTreeRoot(ctx) - require.NoError(t, err) - - // get a new signed block so the root is updated with the new state root - parent.Block.StateRoot = attestedStateRoot[:] - signedParent, err = blocks.NewSignedBeaconBlock(parent) - require.NoError(t, err) - st, err := util.NewBeaconStateAltair() require.NoError(t, err) err = st.SetSlot(slot) require.NoError(t, err) - parentRoot, err := signedParent.Block().HashTreeRoot() - require.NoError(t, err) - - block := util.NewBeaconBlockAltair() - block.Block.Slot = slot - block.Block.ParentRoot = parentRoot[:] - - for i := uint64(0); i < config.SyncCommitteeSize; i++ { - block.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true) - } - - signedBlock, err := blocks.NewSignedBeaconBlock(block) - require.NoError(t, err) - - h, err := signedBlock.Header() - require.NoError(t, err) - - err = st.SetLatestBlockHeader(h.Header) - require.NoError(t, err) - stateRoot, err := st.HashTreeRoot(ctx) - require.NoError(t, err) - - // get a new signed block so the root is updated with the new state root - block.Block.StateRoot = stateRoot[:] - signedBlock, err = blocks.NewSignedBeaconBlock(block) - require.NoError(t, err) - - root, err := block.Block.HashTreeRoot() - require.NoError(t, err) - db := setupDB(t) - updatePeriod := uint64(slot.Sub(1).Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch))) + updatePeriod := uint64(slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch))) update := ðpbv2.LightClientUpdate{ AttestedHeader: ðpbv2.LightClientHeaderContainer{ @@ -334,22 +281,10 @@ func TestLightClientHandler_GetLightClientUpdatesByRangeAltair(t *testing.T) { }) require.NoError(t, err) - mockBlocker := &testutil.MockBlocker{ - RootBlockMap: map[[32]byte]interfaces.ReadOnlySignedBeaconBlock{ - parentRoot: signedParent, - root: signedBlock, - }, - SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{ - slot.Sub(1): signedParent, - slot: signedBlock, - }, - } + mockBlocker := &testutil.MockBlocker{} mockChainService := &mock.ChainService{Optimistic: true, Slot: &slot, State: st} s := &Server{ - Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{ - slot.Sub(1): attestedState, - slot: st, - }}, + Stater: &testutil.MockStater{}, Blocker: mockBlocker, HeadFetcher: mockChainService, BeaconDB: db, @@ -380,69 +315,14 @@ func TestLightClientHandler_GetLightClientUpdatesByRangeCapella(t *testing.T) { config := params.BeaconConfig() slot := primitives.Slot(config.CapellaForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) - attestedState, err := util.NewBeaconStateCapella() - require.NoError(t, err) - err = attestedState.SetSlot(slot.Sub(1)) - require.NoError(t, err) - - parent := util.NewBeaconBlockCapella() - parent.Block.Slot = slot.Sub(1) - - signedParent, err := blocks.NewSignedBeaconBlock(parent) - require.NoError(t, err) - - parentHeader, err := signedParent.Header() - require.NoError(t, err) - attestedHeader := parentHeader.Header - - err = attestedState.SetLatestBlockHeader(attestedHeader) - require.NoError(t, err) - attestedStateRoot, err := attestedState.HashTreeRoot(ctx) - require.NoError(t, err) - - // get a new signed block so the root is updated with the new state root - parent.Block.StateRoot = attestedStateRoot[:] - signedParent, err = blocks.NewSignedBeaconBlock(parent) - require.NoError(t, err) - st, err := util.NewBeaconStateCapella() require.NoError(t, err) err = st.SetSlot(slot) require.NoError(t, err) - parentRoot, err := signedParent.Block().HashTreeRoot() - require.NoError(t, err) - - block := util.NewBeaconBlockCapella() - block.Block.Slot = slot - block.Block.ParentRoot = parentRoot[:] - - for i := uint64(0); i < config.SyncCommitteeSize; i++ { - block.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true) - } - - signedBlock, err := blocks.NewSignedBeaconBlock(block) - require.NoError(t, err) - - h, err := signedBlock.Header() - require.NoError(t, err) - - err = st.SetLatestBlockHeader(h.Header) - require.NoError(t, err) - stateRoot, err := st.HashTreeRoot(ctx) - require.NoError(t, err) - - // get a new signed block so the root is updated with the new state root - block.Block.StateRoot = stateRoot[:] - signedBlock, err = blocks.NewSignedBeaconBlock(block) - require.NoError(t, err) - - root, err := block.Block.HashTreeRoot() - require.NoError(t, err) - db := setupDB(t) - updatePeriod := uint64(slot.Sub(1).Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch))) + updatePeriod := uint64(slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch))) update := ðpbv2.LightClientUpdate{ AttestedHeader: ðpbv2.LightClientHeaderContainer{ @@ -498,22 +378,10 @@ func TestLightClientHandler_GetLightClientUpdatesByRangeCapella(t *testing.T) { }) require.NoError(t, err) - mockBlocker := &testutil.MockBlocker{ - RootBlockMap: map[[32]byte]interfaces.ReadOnlySignedBeaconBlock{ - parentRoot: signedParent, - root: signedBlock, - }, - SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{ - slot.Sub(1): signedParent, - slot: signedBlock, - }, - } + mockBlocker := &testutil.MockBlocker{} mockChainService := &mock.ChainService{Optimistic: true, Slot: &slot, State: st} s := &Server{ - Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{ - slot.Sub(1): attestedState, - slot: st, - }}, + Stater: &testutil.MockStater{}, Blocker: mockBlocker, HeadFetcher: mockChainService, BeaconDB: db, @@ -544,69 +412,14 @@ func TestLightClientHandler_GetLightClientUpdatesByRangeDeneb(t *testing.T) { config := params.BeaconConfig() slot := primitives.Slot(config.DenebForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) - attestedState, err := util.NewBeaconStateDeneb() - require.NoError(t, err) - err = attestedState.SetSlot(slot.Sub(1)) - require.NoError(t, err) - - parent := util.NewBeaconBlockDeneb() - parent.Block.Slot = slot.Sub(1) - - signedParent, err := blocks.NewSignedBeaconBlock(parent) - require.NoError(t, err) - - parentHeader, err := signedParent.Header() - require.NoError(t, err) - attestedHeader := parentHeader.Header - - err = attestedState.SetLatestBlockHeader(attestedHeader) - require.NoError(t, err) - attestedStateRoot, err := attestedState.HashTreeRoot(ctx) - require.NoError(t, err) - - // get a new signed block so the root is updated with the new state root - parent.Block.StateRoot = attestedStateRoot[:] - signedParent, err = blocks.NewSignedBeaconBlock(parent) - require.NoError(t, err) - st, err := util.NewBeaconStateDeneb() require.NoError(t, err) err = st.SetSlot(slot) require.NoError(t, err) - parentRoot, err := signedParent.Block().HashTreeRoot() - require.NoError(t, err) - - block := util.NewBeaconBlockDeneb() - block.Block.Slot = slot - block.Block.ParentRoot = parentRoot[:] - - for i := uint64(0); i < config.SyncCommitteeSize; i++ { - block.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true) - } - - signedBlock, err := blocks.NewSignedBeaconBlock(block) - require.NoError(t, err) - - h, err := signedBlock.Header() - require.NoError(t, err) - - err = st.SetLatestBlockHeader(h.Header) - require.NoError(t, err) - stateRoot, err := st.HashTreeRoot(ctx) - require.NoError(t, err) - - // get a new signed block so the root is updated with the new state root - block.Block.StateRoot = stateRoot[:] - signedBlock, err = blocks.NewSignedBeaconBlock(block) - require.NoError(t, err) - - root, err := block.Block.HashTreeRoot() - require.NoError(t, err) - db := setupDB(t) - updatePeriod := uint64(slot.Sub(1).Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch))) + updatePeriod := uint64(slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch))) update := ðpbv2.LightClientUpdate{ AttestedHeader: ðpbv2.LightClientHeaderContainer{ @@ -662,22 +475,10 @@ func TestLightClientHandler_GetLightClientUpdatesByRangeDeneb(t *testing.T) { }) require.NoError(t, err) - mockBlocker := &testutil.MockBlocker{ - RootBlockMap: map[[32]byte]interfaces.ReadOnlySignedBeaconBlock{ - parentRoot: signedParent, - root: signedBlock, - }, - SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{ - slot.Sub(1): signedParent, - slot: signedBlock, - }, - } + mockBlocker := &testutil.MockBlocker{} mockChainService := &mock.ChainService{Optimistic: true, Slot: &slot, State: st} s := &Server{ - Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{ - slot.Sub(1): attestedState, - slot: st, - }}, + Stater: &testutil.MockStater{}, Blocker: mockBlocker, HeadFetcher: mockChainService, BeaconDB: db, @@ -702,639 +503,1145 @@ func TestLightClientHandler_GetLightClientUpdatesByRangeDeneb(t *testing.T) { require.DeepEqual(t, updateJson, resp.Updates[0].Data) } -//func TestLightClientHandler_GetLightClientUpdatesByRange_TooBigInputCountAltair(t *testing.T) { -// helpers.ClearCache() -// ctx := context.Background() -// config := params.BeaconConfig() -// slot := primitives.Slot(config.AltairForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) -// -// attestedState, err := util.NewBeaconStateAltair() -// require.NoError(t, err) -// err = attestedState.SetSlot(slot.Sub(1)) -// require.NoError(t, err) -// -// parent := util.NewBeaconBlockAltair() -// parent.Block.Slot = slot.Sub(1) -// -// signedParent, err := blocks.NewSignedBeaconBlock(parent) -// require.NoError(t, err) -// -// parentHeader, err := signedParent.Header() -// require.NoError(t, err) -// attestedHeader := parentHeader.Header -// -// err = attestedState.SetLatestBlockHeader(attestedHeader) -// require.NoError(t, err) -// attestedStateRoot, err := attestedState.HashTreeRoot(ctx) -// require.NoError(t, err) -// -// // get a new signed block so the root is updated with the new state root -// parent.Block.StateRoot = attestedStateRoot[:] -// signedParent, err = blocks.NewSignedBeaconBlock(parent) -// require.NoError(t, err) -// -// st, err := util.NewBeaconStateAltair() -// require.NoError(t, err) -// err = st.SetSlot(slot) -// require.NoError(t, err) -// -// parentRoot, err := signedParent.Block().HashTreeRoot() -// require.NoError(t, err) -// -// block := util.NewBeaconBlockAltair() -// block.Block.Slot = slot -// block.Block.ParentRoot = parentRoot[:] -// -// for i := uint64(0); i < config.SyncCommitteeSize; i++ { -// block.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true) -// } -// -// signedBlock, err := blocks.NewSignedBeaconBlock(block) -// require.NoError(t, err) -// -// h, err := signedBlock.Header() -// require.NoError(t, err) -// -// err = st.SetLatestBlockHeader(h.Header) -// require.NoError(t, err) -// stateRoot, err := st.HashTreeRoot(ctx) -// require.NoError(t, err) -// -// // get a new signed block so the root is updated with the new state root -// block.Block.StateRoot = stateRoot[:] -// signedBlock, err = blocks.NewSignedBeaconBlock(block) -// require.NoError(t, err) -// -// root, err := block.Block.HashTreeRoot() -// require.NoError(t, err) -// -// mockBlocker := &testutil.MockBlocker{ -// RootBlockMap: map[[32]byte]interfaces.ReadOnlySignedBeaconBlock{ -// parentRoot: signedParent, -// root: signedBlock, -// }, -// SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{ -// slot.Sub(1): signedParent, -// slot: signedBlock, -// }, -// } -// mockChainService := &mock.ChainService{Optimistic: true, Slot: &slot, State: st} -// s := &Server{ -// Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{ -// slot.Sub(1): attestedState, -// slot: st, -// }}, -// Blocker: mockBlocker, -// HeadFetcher: mockChainService, -// } -// startPeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) -// count := 129 // config.MaxRequestLightClientUpdates is 128 -// url := fmt.Sprintf("http://foo.com/?count=%d&start_period=%d", count, startPeriod) -// request := httptest.NewRequest("GET", url, nil) -// writer := httptest.NewRecorder() -// writer.Body = &bytes.Buffer{} -// -// s.GetLightClientUpdatesByRange(writer, request) -// -// require.Equal(t, http.StatusOK, writer.Code) -// var resp structs.LightClientUpdatesByRangeResponse -// err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) -// require.NoError(t, err) -// var respHeader structs.LightClientHeader -// err = json.Unmarshal(resp.Updates[0].Data.AttestedHeader, &respHeader) -// require.NoError(t, err) -// require.Equal(t, 1, len(resp.Updates)) // Even with big count input, the response is still the max available period, which is 1 in test case. -// require.Equal(t, "altair", resp.Updates[0].Version) -// require.Equal(t, hexutil.Encode(attestedHeader.BodyRoot), respHeader.Beacon.BodyRoot) -// require.NotNil(t, resp) -//} -// -//func TestLightClientHandler_GetLightClientUpdatesByRange_TooBigInputCountCapella(t *testing.T) { -// helpers.ClearCache() -// ctx := context.Background() -// config := params.BeaconConfig() -// slot := primitives.Slot(config.CapellaForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) -// -// attestedState, err := util.NewBeaconStateCapella() -// require.NoError(t, err) -// err = attestedState.SetSlot(slot.Sub(1)) -// require.NoError(t, err) -// -// parent := util.NewBeaconBlockCapella() -// parent.Block.Slot = slot.Sub(1) -// -// signedParent, err := blocks.NewSignedBeaconBlock(parent) -// require.NoError(t, err) -// -// parentHeader, err := signedParent.Header() -// require.NoError(t, err) -// attestedHeader := parentHeader.Header -// -// err = attestedState.SetLatestBlockHeader(attestedHeader) -// require.NoError(t, err) -// attestedStateRoot, err := attestedState.HashTreeRoot(ctx) -// require.NoError(t, err) -// -// // get a new signed block so the root is updated with the new state root -// parent.Block.StateRoot = attestedStateRoot[:] -// signedParent, err = blocks.NewSignedBeaconBlock(parent) -// require.NoError(t, err) -// -// st, err := util.NewBeaconStateCapella() -// require.NoError(t, err) -// err = st.SetSlot(slot) -// require.NoError(t, err) -// -// parentRoot, err := signedParent.Block().HashTreeRoot() -// require.NoError(t, err) -// -// block := util.NewBeaconBlockCapella() -// block.Block.Slot = slot -// block.Block.ParentRoot = parentRoot[:] -// -// for i := uint64(0); i < config.SyncCommitteeSize; i++ { -// block.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true) -// } -// -// signedBlock, err := blocks.NewSignedBeaconBlock(block) -// require.NoError(t, err) -// -// h, err := signedBlock.Header() -// require.NoError(t, err) -// -// err = st.SetLatestBlockHeader(h.Header) -// require.NoError(t, err) -// stateRoot, err := st.HashTreeRoot(ctx) -// require.NoError(t, err) -// -// // get a new signed block so the root is updated with the new state root -// block.Block.StateRoot = stateRoot[:] -// signedBlock, err = blocks.NewSignedBeaconBlock(block) -// require.NoError(t, err) -// -// root, err := block.Block.HashTreeRoot() -// require.NoError(t, err) -// -// mockBlocker := &testutil.MockBlocker{ -// RootBlockMap: map[[32]byte]interfaces.ReadOnlySignedBeaconBlock{ -// parentRoot: signedParent, -// root: signedBlock, -// }, -// SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{ -// slot.Sub(1): signedParent, -// slot: signedBlock, -// }, -// } -// mockChainService := &mock.ChainService{Optimistic: true, Slot: &slot, State: st} -// s := &Server{ -// Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{ -// slot.Sub(1): attestedState, -// slot: st, -// }}, -// Blocker: mockBlocker, -// HeadFetcher: mockChainService, -// } -// startPeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) -// count := 129 // config.MaxRequestLightClientUpdates is 128 -// url := fmt.Sprintf("http://foo.com/?count=%d&start_period=%d", count, startPeriod) -// request := httptest.NewRequest("GET", url, nil) -// writer := httptest.NewRecorder() -// writer.Body = &bytes.Buffer{} -// -// s.GetLightClientUpdatesByRange(writer, request) -// -// require.Equal(t, http.StatusOK, writer.Code) -// var resp structs.LightClientUpdatesByRangeResponse -// err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) -// require.NoError(t, err) -// var respHeader structs.LightClientHeaderCapella -// err = json.Unmarshal(resp.Updates[0].Data.AttestedHeader, &respHeader) -// require.NoError(t, err) -// require.Equal(t, 1, len(resp.Updates)) // Even with big count input, the response is still the max available period, which is 1 in test case. -// require.Equal(t, "capella", resp.Updates[0].Version) -// require.Equal(t, hexutil.Encode(attestedHeader.BodyRoot), respHeader.Beacon.BodyRoot) -// require.NotNil(t, resp) -//} -// -//func TestLightClientHandler_GetLightClientUpdatesByRange_TooBigInputCountDeneb(t *testing.T) { -// helpers.ClearCache() -// ctx := context.Background() -// config := params.BeaconConfig() -// slot := primitives.Slot(config.DenebForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) -// -// attestedState, err := util.NewBeaconStateDeneb() -// require.NoError(t, err) -// err = attestedState.SetSlot(slot.Sub(1)) -// require.NoError(t, err) -// -// parent := util.NewBeaconBlockDeneb() -// parent.Block.Slot = slot.Sub(1) -// -// signedParent, err := blocks.NewSignedBeaconBlock(parent) -// require.NoError(t, err) -// -// parentHeader, err := signedParent.Header() -// require.NoError(t, err) -// attestedHeader := parentHeader.Header -// -// err = attestedState.SetLatestBlockHeader(attestedHeader) -// require.NoError(t, err) -// attestedStateRoot, err := attestedState.HashTreeRoot(ctx) -// require.NoError(t, err) -// -// // get a new signed block so the root is updated with the new state root -// parent.Block.StateRoot = attestedStateRoot[:] -// signedParent, err = blocks.NewSignedBeaconBlock(parent) -// require.NoError(t, err) -// -// st, err := util.NewBeaconStateDeneb() -// require.NoError(t, err) -// err = st.SetSlot(slot) -// require.NoError(t, err) -// -// parentRoot, err := signedParent.Block().HashTreeRoot() -// require.NoError(t, err) -// -// block := util.NewBeaconBlockDeneb() -// block.Block.Slot = slot -// block.Block.ParentRoot = parentRoot[:] -// -// for i := uint64(0); i < config.SyncCommitteeSize; i++ { -// block.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true) -// } -// -// signedBlock, err := blocks.NewSignedBeaconBlock(block) -// require.NoError(t, err) -// -// h, err := signedBlock.Header() -// require.NoError(t, err) -// -// err = st.SetLatestBlockHeader(h.Header) -// require.NoError(t, err) -// stateRoot, err := st.HashTreeRoot(ctx) -// require.NoError(t, err) -// -// // get a new signed block so the root is updated with the new state root -// block.Block.StateRoot = stateRoot[:] -// signedBlock, err = blocks.NewSignedBeaconBlock(block) -// require.NoError(t, err) -// -// root, err := block.Block.HashTreeRoot() -// require.NoError(t, err) -// -// mockBlocker := &testutil.MockBlocker{ -// RootBlockMap: map[[32]byte]interfaces.ReadOnlySignedBeaconBlock{ -// parentRoot: signedParent, -// root: signedBlock, -// }, -// SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{ -// slot.Sub(1): signedParent, -// slot: signedBlock, -// }, -// } -// mockChainService := &mock.ChainService{Optimistic: true, Slot: &slot, State: st} -// s := &Server{ -// Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{ -// slot.Sub(1): attestedState, -// slot: st, -// }}, -// Blocker: mockBlocker, -// HeadFetcher: mockChainService, -// } -// startPeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) -// count := 129 // config.MaxRequestLightClientUpdates is 128 -// url := fmt.Sprintf("http://foo.com/?count=%d&start_period=%d", count, startPeriod) -// request := httptest.NewRequest("GET", url, nil) -// writer := httptest.NewRecorder() -// writer.Body = &bytes.Buffer{} -// -// s.GetLightClientUpdatesByRange(writer, request) -// -// require.Equal(t, http.StatusOK, writer.Code) -// var resp structs.LightClientUpdatesByRangeResponse -// err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) -// require.NoError(t, err) -// var respHeader structs.LightClientHeaderDeneb -// err = json.Unmarshal(resp.Updates[0].Data.AttestedHeader, &respHeader) -// require.NoError(t, err) -// require.Equal(t, 1, len(resp.Updates)) // Even with big count input, the response is still the max available period, which is 1 in test case. -// require.Equal(t, "deneb", resp.Updates[0].Version) -// require.Equal(t, hexutil.Encode(attestedHeader.BodyRoot), respHeader.Beacon.BodyRoot) -// require.NotNil(t, resp) -//} -// -//// TODO - check for not having any blocks from the min period, and startPeriod being too early -//func TestLightClientHandler_GetLightClientUpdatesByRange_TooEarlyPeriodAltair(t *testing.T) { -// helpers.ClearCache() -// ctx := context.Background() -// config := params.BeaconConfig() -// slot := primitives.Slot(config.AltairForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) -// -// attestedState, err := util.NewBeaconStateAltair() -// require.NoError(t, err) -// err = attestedState.SetSlot(slot.Sub(1)) -// require.NoError(t, err) -// -// parent := util.NewBeaconBlockAltair() -// parent.Block.Slot = slot.Sub(1) -// -// signedParent, err := blocks.NewSignedBeaconBlock(parent) -// require.NoError(t, err) -// -// parentHeader, err := signedParent.Header() -// require.NoError(t, err) -// attestedHeader := parentHeader.Header -// -// err = attestedState.SetLatestBlockHeader(attestedHeader) -// require.NoError(t, err) -// attestedStateRoot, err := attestedState.HashTreeRoot(ctx) -// require.NoError(t, err) -// -// // get a new signed block so the root is updated with the new state root -// parent.Block.StateRoot = attestedStateRoot[:] -// signedParent, err = blocks.NewSignedBeaconBlock(parent) -// require.NoError(t, err) -// -// st, err := util.NewBeaconStateAltair() -// require.NoError(t, err) -// err = st.SetSlot(slot) -// require.NoError(t, err) -// -// parentRoot, err := signedParent.Block().HashTreeRoot() -// require.NoError(t, err) -// -// block := util.NewBeaconBlockAltair() -// block.Block.Slot = slot -// block.Block.ParentRoot = parentRoot[:] -// -// for i := uint64(0); i < config.SyncCommitteeSize; i++ { -// block.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true) -// } -// -// signedBlock, err := blocks.NewSignedBeaconBlock(block) -// require.NoError(t, err) -// -// h, err := signedBlock.Header() -// require.NoError(t, err) -// -// err = st.SetLatestBlockHeader(h.Header) -// require.NoError(t, err) -// stateRoot, err := st.HashTreeRoot(ctx) -// require.NoError(t, err) -// -// // get a new signed block so the root is updated with the new state root -// block.Block.StateRoot = stateRoot[:] -// signedBlock, err = blocks.NewSignedBeaconBlock(block) -// require.NoError(t, err) -// -// root, err := block.Block.HashTreeRoot() -// require.NoError(t, err) -// -// mockBlocker := &testutil.MockBlocker{ -// RootBlockMap: map[[32]byte]interfaces.ReadOnlySignedBeaconBlock{ -// parentRoot: signedParent, -// root: signedBlock, -// }, -// SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{ -// slot.Sub(1): signedParent, -// slot: signedBlock, -// }, -// } -// mockChainService := &mock.ChainService{Optimistic: true, Slot: &slot, State: st} -// s := &Server{ -// Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{ -// slot.Sub(1): attestedState, -// slot: st, -// }}, -// Blocker: mockBlocker, -// HeadFetcher: mockChainService, -// } -// startPeriod := 1 // very early period before Altair fork -// count := 1 -// url := fmt.Sprintf("http://foo.com/?count=%d&start_period=%d", count, startPeriod) -// request := httptest.NewRequest("GET", url, nil) -// writer := httptest.NewRecorder() -// writer.Body = &bytes.Buffer{} -// -// s.GetLightClientUpdatesByRange(writer, request) -// -// require.Equal(t, http.StatusOK, writer.Code) -// var resp structs.LightClientUpdatesByRangeResponse -// err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) -// require.NoError(t, err) -// var respHeader structs.LightClientHeader -// err = json.Unmarshal(resp.Updates[0].Data.AttestedHeader, &respHeader) -// require.NoError(t, err) -// require.Equal(t, 1, len(resp.Updates)) -// require.Equal(t, "altair", resp.Updates[0].Version) -// require.Equal(t, hexutil.Encode(attestedHeader.BodyRoot), respHeader.Beacon.BodyRoot) -// require.NotNil(t, resp) -//} -// -//// TODO - same as above -//func TestLightClientHandler_GetLightClientUpdatesByRange_TooBigCountAltair(t *testing.T) { -// helpers.ClearCache() -// ctx := context.Background() -// config := params.BeaconConfig() -// slot := primitives.Slot(config.AltairForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) -// -// attestedState, err := util.NewBeaconStateAltair() -// require.NoError(t, err) -// err = attestedState.SetSlot(slot.Sub(1)) -// require.NoError(t, err) -// -// parent := util.NewBeaconBlockAltair() -// parent.Block.Slot = slot.Sub(1) -// -// signedParent, err := blocks.NewSignedBeaconBlock(parent) -// require.NoError(t, err) -// -// parentHeader, err := signedParent.Header() -// require.NoError(t, err) -// attestedHeader := parentHeader.Header -// -// err = attestedState.SetLatestBlockHeader(attestedHeader) -// require.NoError(t, err) -// attestedStateRoot, err := attestedState.HashTreeRoot(ctx) -// require.NoError(t, err) -// -// // get a new signed block so the root is updated with the new state root -// parent.Block.StateRoot = attestedStateRoot[:] -// signedParent, err = blocks.NewSignedBeaconBlock(parent) -// require.NoError(t, err) -// -// st, err := util.NewBeaconStateAltair() -// require.NoError(t, err) -// err = st.SetSlot(slot) -// require.NoError(t, err) -// -// parentRoot, err := signedParent.Block().HashTreeRoot() -// require.NoError(t, err) -// -// block := util.NewBeaconBlockAltair() -// block.Block.Slot = slot -// block.Block.ParentRoot = parentRoot[:] -// -// for i := uint64(0); i < config.SyncCommitteeSize; i++ { -// block.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true) -// } -// -// signedBlock, err := blocks.NewSignedBeaconBlock(block) -// require.NoError(t, err) -// -// h, err := signedBlock.Header() -// require.NoError(t, err) -// -// err = st.SetLatestBlockHeader(h.Header) -// require.NoError(t, err) -// stateRoot, err := st.HashTreeRoot(ctx) -// require.NoError(t, err) -// -// // get a new signed block so the root is updated with the new state root -// block.Block.StateRoot = stateRoot[:] -// signedBlock, err = blocks.NewSignedBeaconBlock(block) -// require.NoError(t, err) -// -// root, err := block.Block.HashTreeRoot() -// require.NoError(t, err) -// -// mockBlocker := &testutil.MockBlocker{ -// RootBlockMap: map[[32]byte]interfaces.ReadOnlySignedBeaconBlock{ -// parentRoot: signedParent, -// root: signedBlock, -// }, -// SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{ -// slot.Sub(1): signedParent, -// slot: signedBlock, -// }, -// } -// mockChainService := &mock.ChainService{Optimistic: true, Slot: &slot, State: st} -// s := &Server{ -// Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{ -// slot.Sub(1): attestedState, -// slot: st, -// }}, -// Blocker: mockBlocker, -// HeadFetcher: mockChainService, -// } -// startPeriod := 1 // very early period before Altair fork -// count := 10 // This is big count as we only have one period in test case. -// url := fmt.Sprintf("http://foo.com/?count=%d&start_period=%d", count, startPeriod) -// request := httptest.NewRequest("GET", url, nil) -// writer := httptest.NewRecorder() -// writer.Body = &bytes.Buffer{} -// -// s.GetLightClientUpdatesByRange(writer, request) -// -// require.Equal(t, http.StatusOK, writer.Code) -// var resp structs.LightClientUpdatesByRangeResponse -// err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) -// require.NoError(t, err) -// var respHeader structs.LightClientHeader -// err = json.Unmarshal(resp.Updates[0].Data.AttestedHeader, &respHeader) -// require.NoError(t, err) -// require.Equal(t, 1, len(resp.Updates)) -// require.Equal(t, "altair", resp.Updates[0].Version) -// require.Equal(t, hexutil.Encode(attestedHeader.BodyRoot), respHeader.Beacon.BodyRoot) -// require.NotNil(t, resp) -//} -// -//func TestLightClientHandler_GetLightClientUpdatesByRange_BeforeAltair(t *testing.T) { -// helpers.ClearCache() -// ctx := context.Background() -// config := params.BeaconConfig() -// slot := primitives.Slot(config.AltairForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Sub(1) -// -// attestedState, err := util.NewBeaconStateCapella() -// require.NoError(t, err) -// err = attestedState.SetSlot(slot.Sub(1)) -// require.NoError(t, err) -// -// parent := util.NewBeaconBlockCapella() -// parent.Block.Slot = slot.Sub(1) -// -// signedParent, err := blocks.NewSignedBeaconBlock(parent) -// require.NoError(t, err) -// -// parentHeader, err := signedParent.Header() -// require.NoError(t, err) -// attestedHeader := parentHeader.Header -// -// err = attestedState.SetLatestBlockHeader(attestedHeader) -// require.NoError(t, err) -// attestedStateRoot, err := attestedState.HashTreeRoot(ctx) -// require.NoError(t, err) -// -// // get a new signed block so the root is updated with the new state root -// parent.Block.StateRoot = attestedStateRoot[:] -// signedParent, err = blocks.NewSignedBeaconBlock(parent) -// require.NoError(t, err) -// -// st, err := util.NewBeaconStateCapella() -// require.NoError(t, err) -// err = st.SetSlot(slot) -// require.NoError(t, err) -// -// parentRoot, err := signedParent.Block().HashTreeRoot() -// require.NoError(t, err) -// -// block := util.NewBeaconBlockCapella() -// block.Block.Slot = slot -// block.Block.ParentRoot = parentRoot[:] -// -// for i := uint64(0); i < config.SyncCommitteeSize; i++ { -// block.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true) -// } -// -// signedBlock, err := blocks.NewSignedBeaconBlock(block) -// require.NoError(t, err) -// -// h, err := signedBlock.Header() -// require.NoError(t, err) -// -// err = st.SetLatestBlockHeader(h.Header) -// require.NoError(t, err) -// stateRoot, err := st.HashTreeRoot(ctx) -// require.NoError(t, err) -// -// // get a new signed block so the root is updated with the new state root -// block.Block.StateRoot = stateRoot[:] -// signedBlock, err = blocks.NewSignedBeaconBlock(block) -// require.NoError(t, err) -// -// root, err := block.Block.HashTreeRoot() -// require.NoError(t, err) -// -// mockBlocker := &testutil.MockBlocker{ -// RootBlockMap: map[[32]byte]interfaces.ReadOnlySignedBeaconBlock{ -// parentRoot: signedParent, -// root: signedBlock, -// }, -// SlotBlockMap: map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock{ -// slot.Sub(1): signedParent, -// slot: signedBlock, -// }, -// } -// mockChainService := &mock.ChainService{Optimistic: true, Slot: &slot, State: st} -// s := &Server{ -// Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{ -// slot.Sub(1): attestedState, -// slot: st, -// }}, -// Blocker: mockBlocker, -// HeadFetcher: mockChainService, -// } -// startPeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) -// count := 1 -// url := fmt.Sprintf("http://foo.com/?count=%d&start_period=%d", count, startPeriod) -// request := httptest.NewRequest("GET", url, nil) -// writer := httptest.NewRecorder() -// writer.Body = &bytes.Buffer{} -// -// s.GetLightClientUpdatesByRange(writer, request) -// -// require.Equal(t, http.StatusNotFound, writer.Code) -//} +func TestLightClientHandler_GetLightClientUpdatesByRangeMultipleAltair(t *testing.T) { + helpers.ClearCache() + ctx := context.Background() + config := params.BeaconConfig() + slot := primitives.Slot(config.AltairForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) + + st, err := util.NewBeaconStateAltair() + require.NoError(t, err) + headSlot := slot.Add(820000) + err = st.SetSlot(headSlot) + require.NoError(t, err) + + db := setupDB(t) + + updates := make([]*ethpbv2.LightClientUpdate, 100) + + updatePeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) + + for i := 0; i < 100; i++ { + newSlot := slot.Add(uint64(i)) + + update := ðpbv2.LightClientUpdate{ + AttestedHeader: ðpbv2.LightClientHeaderContainer{ + Header: ðpbv2.LightClientHeaderContainer_HeaderAltair{ + HeaderAltair: ðpbv2.LightClientHeader{ + Beacon: ðpbv1.BeaconBlockHeader{ + Slot: newSlot, + ProposerIndex: 1, + ParentRoot: []byte{1, 1, 1}, + StateRoot: []byte{1, 1, 1}, + BodyRoot: []byte{1, 1, 1}, + }, + }, + }, + }, + NextSyncCommittee: ðpbv2.SyncCommittee{ + Pubkeys: nil, + AggregatePubkey: nil, + }, + NextSyncCommitteeBranch: nil, + FinalizedHeader: nil, + FinalityBranch: nil, + SyncAggregate: ðpbv1.SyncAggregate{ + SyncCommitteeBits: []byte{1, 1, 1}, + SyncCommitteeSignature: []byte{1, 1, 1}, + }, + SignatureSlot: 7, + } + + updates[i] = update + + err = db.SaveLightClientUpdate(ctx, uint64(updatePeriod), ðpbv2.LightClientUpdateWithVersion{ + Version: version.Altair, + Data: update, + }) + require.NoError(t, err) + + updatePeriod++ + } + + mockBlocker := &testutil.MockBlocker{} + mockChainService := &mock.ChainService{Optimistic: true, Slot: &headSlot, State: st} + s := &Server{ + Stater: &testutil.MockStater{}, + Blocker: mockBlocker, + HeadFetcher: mockChainService, + BeaconDB: db, + } + startPeriod := slot.Sub(1).Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) + url := fmt.Sprintf("http://foo.com/?count=100&start_period=%d", startPeriod) + request := httptest.NewRequest("GET", url, nil) + writer := httptest.NewRecorder() + writer.Body = &bytes.Buffer{} + + s.GetLightClientUpdatesByRange(writer, request) + + require.Equal(t, http.StatusOK, writer.Code) + var resp structs.LightClientUpdatesByRangeResponse + err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) + require.NoError(t, err) + require.Equal(t, 100, len(resp.Updates)) + require.NoError(t, err) + for i, update := range updates { + require.Equal(t, "altair", resp.Updates[i].Version) + updateJson, err := structs.LightClientUpdateFromConsensus(update) + require.NoError(t, err) + require.DeepEqual(t, updateJson, resp.Updates[i].Data) + } +} + +func TestLightClientHandler_GetLightClientUpdatesByRangeMultipleCapella(t *testing.T) { + helpers.ClearCache() + ctx := context.Background() + config := params.BeaconConfig() + slot := primitives.Slot(config.CapellaForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) + + st, err := util.NewBeaconStateAltair() + require.NoError(t, err) + headSlot := slot.Add(820000) + err = st.SetSlot(headSlot) + require.NoError(t, err) + + db := setupDB(t) + + updates := make([]*ethpbv2.LightClientUpdate, 100) + + updatePeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) + + for i := 0; i < 100; i++ { + + newSlot := slot.Add(uint64(i)) + + update := ðpbv2.LightClientUpdate{ + AttestedHeader: ðpbv2.LightClientHeaderContainer{ + Header: ðpbv2.LightClientHeaderContainer_HeaderCapella{ + HeaderCapella: ðpbv2.LightClientHeaderCapella{ + Beacon: ðpbv1.BeaconBlockHeader{ + Slot: newSlot, + ProposerIndex: 1, + ParentRoot: []byte{1, 1, 1}, + StateRoot: []byte{1, 1, 1}, + BodyRoot: []byte{1, 1, 1}, + }, + Execution: &enginev1.ExecutionPayloadHeaderCapella{ + FeeRecipient: []byte{1, 2, 3}, + }, + ExecutionBranch: [][]byte{{1, 2, 3}, {4, 5, 6}}, + }, + }, + }, + NextSyncCommittee: ðpbv2.SyncCommittee{ + Pubkeys: nil, + AggregatePubkey: nil, + }, + NextSyncCommitteeBranch: nil, + FinalizedHeader: ðpbv2.LightClientHeaderContainer{ + Header: ðpbv2.LightClientHeaderContainer_HeaderCapella{ + HeaderCapella: ðpbv2.LightClientHeaderCapella{ + Beacon: ðpbv1.BeaconBlockHeader{ + Slot: 12, + ProposerIndex: 1, + ParentRoot: []byte{1, 1, 1}, + StateRoot: []byte{1, 1, 1}, + BodyRoot: []byte{1, 1, 1}, + }, + Execution: &enginev1.ExecutionPayloadHeaderCapella{ + FeeRecipient: []byte{1, 2, 3}, + }, + ExecutionBranch: [][]byte{{1, 2, 3}, {4, 5, 6}}, + }, + }, + }, + FinalityBranch: nil, + SyncAggregate: ðpbv1.SyncAggregate{ + SyncCommitteeBits: []byte{1, 1, 1}, + SyncCommitteeSignature: []byte{1, 1, 1}, + }, + SignatureSlot: 7, + } + + updates[i] = update + + err = db.SaveLightClientUpdate(ctx, uint64(updatePeriod), ðpbv2.LightClientUpdateWithVersion{ + Version: version.Capella, + Data: update, + }) + require.NoError(t, err) + + updatePeriod++ + } + + mockBlocker := &testutil.MockBlocker{} + mockChainService := &mock.ChainService{Optimistic: true, Slot: &headSlot, State: st} + s := &Server{ + Stater: &testutil.MockStater{}, + Blocker: mockBlocker, + HeadFetcher: mockChainService, + BeaconDB: db, + } + startPeriod := slot.Sub(1).Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) + url := fmt.Sprintf("http://foo.com/?count=100&start_period=%d", startPeriod) + request := httptest.NewRequest("GET", url, nil) + writer := httptest.NewRecorder() + writer.Body = &bytes.Buffer{} + + s.GetLightClientUpdatesByRange(writer, request) + + require.Equal(t, http.StatusOK, writer.Code) + var resp structs.LightClientUpdatesByRangeResponse + err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) + require.NoError(t, err) + require.Equal(t, 100, len(resp.Updates)) + require.NoError(t, err) + for i, update := range updates { + require.Equal(t, "capella", resp.Updates[i].Version) + updateJson, err := structs.LightClientUpdateFromConsensus(update) + require.NoError(t, err) + require.DeepEqual(t, updateJson, resp.Updates[i].Data) + } +} + +func TestLightClientHandler_GetLightClientUpdatesByRangeMultipleDeneb(t *testing.T) { + helpers.ClearCache() + ctx := context.Background() + config := params.BeaconConfig() + slot := primitives.Slot(config.DenebForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) + + st, err := util.NewBeaconStateAltair() + require.NoError(t, err) + headSlot := slot.Add(820000) + err = st.SetSlot(headSlot) + require.NoError(t, err) + + db := setupDB(t) + + updates := make([]*ethpbv2.LightClientUpdate, 100) + + updatePeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) + + for i := 0; i < 100; i++ { + + newSlot := slot.Add(uint64(i)) + + update := ðpbv2.LightClientUpdate{ + AttestedHeader: ðpbv2.LightClientHeaderContainer{ + Header: ðpbv2.LightClientHeaderContainer_HeaderDeneb{ + HeaderDeneb: ðpbv2.LightClientHeaderDeneb{ + Beacon: ðpbv1.BeaconBlockHeader{ + Slot: newSlot, + ProposerIndex: 1, + ParentRoot: []byte{1, 1, 1}, + StateRoot: []byte{1, 1, 1}, + BodyRoot: []byte{1, 1, 1}, + }, + Execution: &enginev1.ExecutionPayloadHeaderDeneb{ + FeeRecipient: []byte{1, 2, 3}, + }, + ExecutionBranch: [][]byte{{1, 2, 3}, {4, 5, 6}}, + }, + }, + }, + NextSyncCommittee: ðpbv2.SyncCommittee{ + Pubkeys: nil, + AggregatePubkey: nil, + }, + NextSyncCommitteeBranch: nil, + FinalizedHeader: ðpbv2.LightClientHeaderContainer{ + Header: ðpbv2.LightClientHeaderContainer_HeaderDeneb{ + HeaderDeneb: ðpbv2.LightClientHeaderDeneb{ + Beacon: ðpbv1.BeaconBlockHeader{ + Slot: 12, + ProposerIndex: 1, + ParentRoot: []byte{1, 1, 1}, + StateRoot: []byte{1, 1, 1}, + BodyRoot: []byte{1, 1, 1}, + }, + Execution: &enginev1.ExecutionPayloadHeaderDeneb{ + FeeRecipient: []byte{1, 2, 3}, + }, + ExecutionBranch: [][]byte{{1, 2, 3}, {4, 5, 6}}, + }, + }, + }, + FinalityBranch: nil, + SyncAggregate: ðpbv1.SyncAggregate{ + SyncCommitteeBits: []byte{1, 1, 1}, + SyncCommitteeSignature: []byte{1, 1, 1}, + }, + SignatureSlot: 7, + } + + updates[i] = update + + err = db.SaveLightClientUpdate(ctx, uint64(updatePeriod), ðpbv2.LightClientUpdateWithVersion{ + Version: version.Deneb, + Data: update, + }) + require.NoError(t, err) + + updatePeriod++ + } + + mockBlocker := &testutil.MockBlocker{} + mockChainService := &mock.ChainService{Optimistic: true, Slot: &headSlot, State: st} + s := &Server{ + Stater: &testutil.MockStater{}, + Blocker: mockBlocker, + HeadFetcher: mockChainService, + BeaconDB: db, + } + startPeriod := slot.Sub(1).Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) + url := fmt.Sprintf("http://foo.com/?count=100&start_period=%d", startPeriod) + request := httptest.NewRequest("GET", url, nil) + writer := httptest.NewRecorder() + writer.Body = &bytes.Buffer{} + + s.GetLightClientUpdatesByRange(writer, request) + + require.Equal(t, http.StatusOK, writer.Code) + var resp structs.LightClientUpdatesByRangeResponse + err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) + require.NoError(t, err) + require.Equal(t, 100, len(resp.Updates)) + require.NoError(t, err) + for i, update := range updates { + require.Equal(t, "deneb", resp.Updates[i].Version) + updateJson, err := structs.LightClientUpdateFromConsensus(update) + require.NoError(t, err) + require.DeepEqual(t, updateJson, resp.Updates[i].Data) + } +} + +func TestLightClientHandler_GetLightClientUpdatesByRangeMultipleForksAltairCapella(t *testing.T) { + helpers.ClearCache() + ctx := context.Background() + config := params.BeaconConfig() + slot := primitives.Slot(config.CapellaForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) + + st, err := util.NewBeaconStateAltair() + require.NoError(t, err) + headSlot := slot.Add(820000) + err = st.SetSlot(headSlot) + require.NoError(t, err) + + db := setupDB(t) + + updates := make([]*ethpbv2.LightClientUpdate, 100) + + updatePeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) + updatePeriod-- + for i := 1; i < 51; i++ { + + newSlot := slot.Sub(uint64(i)) + + update := ðpbv2.LightClientUpdate{ + AttestedHeader: ðpbv2.LightClientHeaderContainer{ + Header: ðpbv2.LightClientHeaderContainer_HeaderAltair{ + HeaderAltair: ðpbv2.LightClientHeader{ + Beacon: ðpbv1.BeaconBlockHeader{ + Slot: newSlot, + ProposerIndex: 1, + ParentRoot: []byte{1, 1, 1}, + StateRoot: []byte{1, 1, 1}, + BodyRoot: []byte{1, 1, 1}, + }, + }, + }, + }, + NextSyncCommittee: ðpbv2.SyncCommittee{ + Pubkeys: nil, + AggregatePubkey: nil, + }, + NextSyncCommitteeBranch: nil, + FinalizedHeader: ðpbv2.LightClientHeaderContainer{ + Header: ðpbv2.LightClientHeaderContainer_HeaderAltair{ + HeaderAltair: ðpbv2.LightClientHeader{ + Beacon: ðpbv1.BeaconBlockHeader{ + Slot: 12, + ProposerIndex: 1, + ParentRoot: []byte{1, 1, 1}, + StateRoot: []byte{1, 1, 1}, + BodyRoot: []byte{1, 1, 1}, + }, + }, + }, + }, + FinalityBranch: nil, + SyncAggregate: ðpbv1.SyncAggregate{ + SyncCommitteeBits: []byte{1, 1, 1}, + SyncCommitteeSignature: []byte{1, 1, 1}, + }, + SignatureSlot: newSlot, + } + + updates[50-i] = update + + err = db.SaveLightClientUpdate(ctx, uint64(updatePeriod), ðpbv2.LightClientUpdateWithVersion{ + Version: version.Altair, + Data: update, + }) + require.NoError(t, err) + + updatePeriod-- + } + + updatePeriod = slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) + + for i := 50; i < 100; i++ { + + newSlot := slot.Add(uint64(i)) + + update := ðpbv2.LightClientUpdate{ + AttestedHeader: ðpbv2.LightClientHeaderContainer{ + Header: ðpbv2.LightClientHeaderContainer_HeaderCapella{ + HeaderCapella: ðpbv2.LightClientHeaderCapella{ + Beacon: ðpbv1.BeaconBlockHeader{ + Slot: newSlot, + ProposerIndex: 1, + ParentRoot: []byte{1, 1, 1}, + StateRoot: []byte{1, 1, 1}, + BodyRoot: []byte{1, 1, 1}, + }, + Execution: &enginev1.ExecutionPayloadHeaderCapella{ + FeeRecipient: []byte{1, 2, 3}, + }, + ExecutionBranch: [][]byte{{1, 2, 3}, {4, 5, 6}}, + }, + }, + }, + NextSyncCommittee: ðpbv2.SyncCommittee{ + Pubkeys: nil, + AggregatePubkey: nil, + }, + NextSyncCommitteeBranch: nil, + FinalizedHeader: ðpbv2.LightClientHeaderContainer{ + Header: ðpbv2.LightClientHeaderContainer_HeaderCapella{ + HeaderCapella: ðpbv2.LightClientHeaderCapella{ + Beacon: ðpbv1.BeaconBlockHeader{ + Slot: 12, + ProposerIndex: 1, + ParentRoot: []byte{1, 1, 1}, + StateRoot: []byte{1, 1, 1}, + BodyRoot: []byte{1, 1, 1}, + }, + Execution: &enginev1.ExecutionPayloadHeaderCapella{ + FeeRecipient: []byte{1, 2, 3}, + }, + ExecutionBranch: [][]byte{{1, 2, 3}, {4, 5, 6}}, + }, + }, + }, + FinalityBranch: nil, + SyncAggregate: ðpbv1.SyncAggregate{ + SyncCommitteeBits: []byte{1, 1, 1}, + SyncCommitteeSignature: []byte{1, 1, 1}, + }, + SignatureSlot: newSlot, + } + + updates[i] = update + + err = db.SaveLightClientUpdate(ctx, uint64(updatePeriod), ðpbv2.LightClientUpdateWithVersion{ + Version: version.Capella, + Data: update, + }) + require.NoError(t, err) + + updatePeriod++ + } + + mockBlocker := &testutil.MockBlocker{} + mockChainService := &mock.ChainService{Optimistic: true, Slot: &headSlot, State: st} + s := &Server{ + Stater: &testutil.MockStater{}, + Blocker: mockBlocker, + HeadFetcher: mockChainService, + BeaconDB: db, + } + startPeriod := slot.Sub(1).Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) + url := fmt.Sprintf("http://foo.com/?count=100&start_period=%d", startPeriod.Sub(50)) + request := httptest.NewRequest("GET", url, nil) + writer := httptest.NewRecorder() + writer.Body = &bytes.Buffer{} + + s.GetLightClientUpdatesByRange(writer, request) + + require.Equal(t, http.StatusOK, writer.Code) + var resp structs.LightClientUpdatesByRangeResponse + err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) + require.NoError(t, err) + require.Equal(t, 100, len(resp.Updates)) + require.NoError(t, err) + for i, update := range updates { + if i < 50 { + require.Equal(t, "altair", resp.Updates[i].Version) + } else { + require.Equal(t, "capella", resp.Updates[i].Version) + } + updateJson, err := structs.LightClientUpdateFromConsensus(update) + require.NoError(t, err) + require.DeepEqual(t, updateJson, resp.Updates[i].Data) + } +} + +func TestLightClientHandler_GetLightClientUpdatesByRangeMultipleForksCapellaDeneb(t *testing.T) { + helpers.ClearCache() + ctx := context.Background() + config := params.BeaconConfig() + slot := primitives.Slot(config.DenebForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) + + st, err := util.NewBeaconStateAltair() + require.NoError(t, err) + headSlot := slot.Add(820000) + err = st.SetSlot(headSlot) + require.NoError(t, err) + + db := setupDB(t) + + updates := make([]*ethpbv2.LightClientUpdate, 100) + + updatePeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) + updatePeriod-- + for i := 1; i < 51; i++ { + + newSlot := slot.Sub(uint64(i)) + + update := ðpbv2.LightClientUpdate{ + AttestedHeader: ðpbv2.LightClientHeaderContainer{ + Header: ðpbv2.LightClientHeaderContainer_HeaderCapella{ + HeaderCapella: ðpbv2.LightClientHeaderCapella{ + Beacon: ðpbv1.BeaconBlockHeader{ + Slot: newSlot, + ProposerIndex: 1, + ParentRoot: []byte{1, 1, 1}, + StateRoot: []byte{1, 1, 1}, + BodyRoot: []byte{1, 1, 1}, + }, + Execution: &enginev1.ExecutionPayloadHeaderCapella{ + FeeRecipient: []byte{1, 2, 3}, + }, + ExecutionBranch: [][]byte{{1, 2, 3}, {4, 5, 6}}, + }, + }, + }, + NextSyncCommittee: ðpbv2.SyncCommittee{ + Pubkeys: nil, + AggregatePubkey: nil, + }, + NextSyncCommitteeBranch: nil, + FinalizedHeader: ðpbv2.LightClientHeaderContainer{ + Header: ðpbv2.LightClientHeaderContainer_HeaderCapella{ + HeaderCapella: ðpbv2.LightClientHeaderCapella{ + Beacon: ðpbv1.BeaconBlockHeader{ + Slot: 12, + ProposerIndex: 1, + ParentRoot: []byte{1, 1, 1}, + StateRoot: []byte{1, 1, 1}, + BodyRoot: []byte{1, 1, 1}, + }, + Execution: &enginev1.ExecutionPayloadHeaderCapella{ + FeeRecipient: []byte{1, 2, 3}, + }, + ExecutionBranch: [][]byte{{1, 2, 3}, {4, 5, 6}}, + }, + }, + }, + FinalityBranch: nil, + SyncAggregate: ðpbv1.SyncAggregate{ + SyncCommitteeBits: []byte{1, 1, 1}, + SyncCommitteeSignature: []byte{1, 1, 1}, + }, + SignatureSlot: newSlot, + } + + updates[50-i] = update + + err = db.SaveLightClientUpdate(ctx, uint64(updatePeriod), ðpbv2.LightClientUpdateWithVersion{ + Version: version.Capella, + Data: update, + }) + require.NoError(t, err) + + updatePeriod-- + } + + updatePeriod = slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) + + for i := 50; i < 100; i++ { + + newSlot := slot.Add(uint64(i)) + + update := ðpbv2.LightClientUpdate{ + AttestedHeader: ðpbv2.LightClientHeaderContainer{ + Header: ðpbv2.LightClientHeaderContainer_HeaderDeneb{ + HeaderDeneb: ðpbv2.LightClientHeaderDeneb{ + Beacon: ðpbv1.BeaconBlockHeader{ + Slot: newSlot, + ProposerIndex: 1, + ParentRoot: []byte{1, 1, 1}, + StateRoot: []byte{1, 1, 1}, + BodyRoot: []byte{1, 1, 1}, + }, + Execution: &enginev1.ExecutionPayloadHeaderDeneb{ + FeeRecipient: []byte{1, 2, 3}, + }, + ExecutionBranch: [][]byte{{1, 2, 3}, {4, 5, 6}}, + }, + }, + }, + NextSyncCommittee: ðpbv2.SyncCommittee{ + Pubkeys: nil, + AggregatePubkey: nil, + }, + NextSyncCommitteeBranch: nil, + FinalizedHeader: ðpbv2.LightClientHeaderContainer{ + Header: ðpbv2.LightClientHeaderContainer_HeaderDeneb{ + HeaderDeneb: ðpbv2.LightClientHeaderDeneb{ + Beacon: ðpbv1.BeaconBlockHeader{ + Slot: 12, + ProposerIndex: 1, + ParentRoot: []byte{1, 1, 1}, + StateRoot: []byte{1, 1, 1}, + BodyRoot: []byte{1, 1, 1}, + }, + Execution: &enginev1.ExecutionPayloadHeaderDeneb{ + FeeRecipient: []byte{1, 2, 3}, + }, + ExecutionBranch: [][]byte{{1, 2, 3}, {4, 5, 6}}, + }, + }, + }, + FinalityBranch: nil, + SyncAggregate: ðpbv1.SyncAggregate{ + SyncCommitteeBits: []byte{1, 1, 1}, + SyncCommitteeSignature: []byte{1, 1, 1}, + }, + SignatureSlot: newSlot, + } + + updates[i] = update + + err = db.SaveLightClientUpdate(ctx, uint64(updatePeriod), ðpbv2.LightClientUpdateWithVersion{ + Version: version.Deneb, + Data: update, + }) + require.NoError(t, err) + + updatePeriod++ + } + + mockBlocker := &testutil.MockBlocker{} + mockChainService := &mock.ChainService{Optimistic: true, Slot: &headSlot, State: st} + s := &Server{ + Stater: &testutil.MockStater{}, + Blocker: mockBlocker, + HeadFetcher: mockChainService, + BeaconDB: db, + } + startPeriod := slot.Sub(1).Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) + url := fmt.Sprintf("http://foo.com/?count=100&start_period=%d", startPeriod.Sub(50)) + request := httptest.NewRequest("GET", url, nil) + writer := httptest.NewRecorder() + writer.Body = &bytes.Buffer{} + + s.GetLightClientUpdatesByRange(writer, request) + + require.Equal(t, http.StatusOK, writer.Code) + var resp structs.LightClientUpdatesByRangeResponse + err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) + require.NoError(t, err) + require.Equal(t, 100, len(resp.Updates)) + require.NoError(t, err) + for i, update := range updates { + if i < 50 { + require.Equal(t, "capella", resp.Updates[i].Version) + } else { + require.Equal(t, "deneb", resp.Updates[i].Version) + } + updateJson, err := structs.LightClientUpdateFromConsensus(update) + require.NoError(t, err) + require.DeepEqual(t, updateJson, resp.Updates[i].Data) + } +} + +func TestLightClientHandler_GetLightClientUpdatesByRangeCountBiggerThanLimit(t *testing.T) { + helpers.ClearCache() + ctx := context.Background() + config := params.BeaconConfig() + slot := primitives.Slot(config.AltairForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) + + st, err := util.NewBeaconStateAltair() + require.NoError(t, err) + headSlot := slot.Add(5000000) + err = st.SetSlot(headSlot) + require.NoError(t, err) + + db := setupDB(t) + + updates := make([]*ethpbv2.LightClientUpdate, 150) + + updatePeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) + + for i := 0; i < 150; i++ { + newSlot := slot.Add(uint64(i)) + + update := ðpbv2.LightClientUpdate{ + AttestedHeader: ðpbv2.LightClientHeaderContainer{ + Header: ðpbv2.LightClientHeaderContainer_HeaderAltair{ + HeaderAltair: ðpbv2.LightClientHeader{ + Beacon: ðpbv1.BeaconBlockHeader{ + Slot: newSlot, + ProposerIndex: 1, + ParentRoot: []byte{1, 1, 1}, + StateRoot: []byte{1, 1, 1}, + BodyRoot: []byte{1, 1, 1}, + }, + }, + }, + }, + NextSyncCommittee: ðpbv2.SyncCommittee{ + Pubkeys: nil, + AggregatePubkey: nil, + }, + NextSyncCommitteeBranch: nil, + FinalizedHeader: nil, + FinalityBranch: nil, + SyncAggregate: ðpbv1.SyncAggregate{ + SyncCommitteeBits: []byte{1, 1, 1}, + SyncCommitteeSignature: []byte{1, 1, 1}, + }, + SignatureSlot: 7, + } + + updates[i] = update + + err = db.SaveLightClientUpdate(ctx, uint64(updatePeriod), ðpbv2.LightClientUpdateWithVersion{ + Version: version.Altair, + Data: update, + }) + require.NoError(t, err) + + updatePeriod++ + } + + mockBlocker := &testutil.MockBlocker{} + mockChainService := &mock.ChainService{Optimistic: true, Slot: &headSlot, State: st} + s := &Server{ + Stater: &testutil.MockStater{}, + Blocker: mockBlocker, + HeadFetcher: mockChainService, + BeaconDB: db, + } + startPeriod := slot.Sub(1).Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) + url := fmt.Sprintf("http://foo.com/?count=150&start_period=%d", startPeriod) + request := httptest.NewRequest("GET", url, nil) + writer := httptest.NewRecorder() + writer.Body = &bytes.Buffer{} + + s.GetLightClientUpdatesByRange(writer, request) + + require.Equal(t, http.StatusOK, writer.Code) + var resp structs.LightClientUpdatesByRangeResponse + err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) + require.NoError(t, err) + require.Equal(t, 128, len(resp.Updates)) + require.NoError(t, err) + for i, update := range updates { + if i < 128 { + require.Equal(t, "altair", resp.Updates[i].Version) + updateJson, err := structs.LightClientUpdateFromConsensus(update) + require.NoError(t, err) + require.DeepEqual(t, updateJson, resp.Updates[i].Data) + } + } +} + +func TestLightClientHandler_GetLightClientUpdatesByRangeCountBiggerThanMax(t *testing.T) { + helpers.ClearCache() + ctx := context.Background() + config := params.BeaconConfig() + slot := primitives.Slot(config.AltairForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) + + st, err := util.NewBeaconStateAltair() + require.NoError(t, err) + headSlot := slot.Add(900000) + err = st.SetSlot(headSlot) + require.NoError(t, err) + + db := setupDB(t) + + updates := make([]*ethpbv2.LightClientUpdate, 150) + + updatePeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) + + for i := 0; i < 150; i++ { + newSlot := slot.Add(uint64(i)) + + update := ðpbv2.LightClientUpdate{ + AttestedHeader: ðpbv2.LightClientHeaderContainer{ + Header: ðpbv2.LightClientHeaderContainer_HeaderAltair{ + HeaderAltair: ðpbv2.LightClientHeader{ + Beacon: ðpbv1.BeaconBlockHeader{ + Slot: newSlot, + ProposerIndex: 1, + ParentRoot: []byte{1, 1, 1}, + StateRoot: []byte{1, 1, 1}, + BodyRoot: []byte{1, 1, 1}, + }, + }, + }, + }, + NextSyncCommittee: ðpbv2.SyncCommittee{ + Pubkeys: nil, + AggregatePubkey: nil, + }, + NextSyncCommitteeBranch: nil, + FinalizedHeader: nil, + FinalityBranch: nil, + SyncAggregate: ðpbv1.SyncAggregate{ + SyncCommitteeBits: []byte{1, 1, 1}, + SyncCommitteeSignature: []byte{1, 1, 1}, + }, + SignatureSlot: 7, + } + + updates[i] = update + + err = db.SaveLightClientUpdate(ctx, uint64(updatePeriod), ðpbv2.LightClientUpdateWithVersion{ + Version: version.Altair, + Data: update, + }) + require.NoError(t, err) + + updatePeriod++ + } + + mockBlocker := &testutil.MockBlocker{} + mockChainService := &mock.ChainService{Optimistic: true, Slot: &headSlot, State: st} + s := &Server{ + Stater: &testutil.MockStater{}, + Blocker: mockBlocker, + HeadFetcher: mockChainService, + BeaconDB: db, + } + startPeriod := slot.Sub(1).Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) + url := fmt.Sprintf("http://foo.com/?count=150&start_period=%d", startPeriod) + request := httptest.NewRequest("GET", url, nil) + writer := httptest.NewRecorder() + writer.Body = &bytes.Buffer{} + + s.GetLightClientUpdatesByRange(writer, request) + + maxSlot := slot.Add(900000).Div(uint64(config.SlotsPerEpoch)).Div(uint64(config.EpochsPerSyncCommitteePeriod)) + updatePeriod = slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) + diffSlots := maxSlot - updatePeriod + 1 + + require.Equal(t, http.StatusOK, writer.Code) + var resp structs.LightClientUpdatesByRangeResponse + err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) + require.NoError(t, err) + require.Equal(t, int(diffSlots), len(resp.Updates)) + require.NoError(t, err) + for i, update := range updates { + if i < int(diffSlots) { + require.Equal(t, "altair", resp.Updates[i].Version) + updateJson, err := structs.LightClientUpdateFromConsensus(update) + require.NoError(t, err) + require.DeepEqual(t, updateJson, resp.Updates[i].Data) + } + } +} + +func TestLightClientHandler_GetLightClientUpdatesByRangeStartPeriodBeforeAltair(t *testing.T) { + helpers.ClearCache() + ctx := context.Background() + config := params.BeaconConfig() + slot := primitives.Slot(config.AltairForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) + + st, err := util.NewBeaconStateAltair() + require.NoError(t, err) + headSlot := slot.Add(820000) + err = st.SetSlot(headSlot) + require.NoError(t, err) + + db := setupDB(t) + + updates := make([]*ethpbv2.LightClientUpdate, 100) + + updatePeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) + + for i := 0; i < 100; i++ { + newSlot := slot.Add(uint64(i)) + + update := ðpbv2.LightClientUpdate{ + AttestedHeader: ðpbv2.LightClientHeaderContainer{ + Header: ðpbv2.LightClientHeaderContainer_HeaderAltair{ + HeaderAltair: ðpbv2.LightClientHeader{ + Beacon: ðpbv1.BeaconBlockHeader{ + Slot: newSlot, + ProposerIndex: 1, + ParentRoot: []byte{1, 1, 1}, + StateRoot: []byte{1, 1, 1}, + BodyRoot: []byte{1, 1, 1}, + }, + }, + }, + }, + NextSyncCommittee: ðpbv2.SyncCommittee{ + Pubkeys: nil, + AggregatePubkey: nil, + }, + NextSyncCommitteeBranch: nil, + FinalizedHeader: nil, + FinalityBranch: nil, + SyncAggregate: ðpbv1.SyncAggregate{ + SyncCommitteeBits: []byte{1, 1, 1}, + SyncCommitteeSignature: []byte{1, 1, 1}, + }, + SignatureSlot: 7, + } + + updates[i] = update + + err = db.SaveLightClientUpdate(ctx, uint64(updatePeriod), ðpbv2.LightClientUpdateWithVersion{ + Version: version.Altair, + Data: update, + }) + require.NoError(t, err) + + updatePeriod++ + } + + mockBlocker := &testutil.MockBlocker{} + mockChainService := &mock.ChainService{Optimistic: true, Slot: &headSlot, State: st} + s := &Server{ + Stater: &testutil.MockStater{}, + Blocker: mockBlocker, + HeadFetcher: mockChainService, + BeaconDB: db, + } + startPeriod := slot.Sub(1).Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) + url := fmt.Sprintf("http://foo.com/?count=100&start_period=%d", startPeriod-20) + request := httptest.NewRequest("GET", url, nil) + writer := httptest.NewRecorder() + writer.Body = &bytes.Buffer{} + + s.GetLightClientUpdatesByRange(writer, request) + + require.Equal(t, http.StatusOK, writer.Code) + var resp structs.LightClientUpdatesByRangeResponse + err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) + require.NoError(t, err) + require.Equal(t, 100, len(resp.Updates)) + require.NoError(t, err) + for i, update := range updates { + require.Equal(t, "altair", resp.Updates[i].Version) + updateJson, err := structs.LightClientUpdateFromConsensus(update) + require.NoError(t, err) + require.DeepEqual(t, updateJson, resp.Updates[i].Data) + } +} + +func TestLightClientHandler_GetLightClientUpdatesByRangeMissingUpdates(t *testing.T) { + helpers.ClearCache() + ctx := context.Background() + config := params.BeaconConfig() + slot := primitives.Slot(config.AltairForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) + + st, err := util.NewBeaconStateAltair() + require.NoError(t, err) + headSlot := slot.Add(820000) + err = st.SetSlot(headSlot) + require.NoError(t, err) + + db := setupDB(t) + + updates := make([]*ethpbv2.LightClientUpdate, 100) + + updatePeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) + + validUpdatesLen := 70 + + for i := 0; i < 100; i++ { + if i == validUpdatesLen { // skip this update + updatePeriod++ + continue + } + newSlot := slot.Add(uint64(i)) + + update := ðpbv2.LightClientUpdate{ + AttestedHeader: ðpbv2.LightClientHeaderContainer{ + Header: ðpbv2.LightClientHeaderContainer_HeaderAltair{ + HeaderAltair: ðpbv2.LightClientHeader{ + Beacon: ðpbv1.BeaconBlockHeader{ + Slot: newSlot, + ProposerIndex: 1, + ParentRoot: []byte{1, 1, 1}, + StateRoot: []byte{1, 1, 1}, + BodyRoot: []byte{1, 1, 1}, + }, + }, + }, + }, + NextSyncCommittee: ðpbv2.SyncCommittee{ + Pubkeys: nil, + AggregatePubkey: nil, + }, + NextSyncCommitteeBranch: nil, + FinalizedHeader: nil, + FinalityBranch: nil, + SyncAggregate: ðpbv1.SyncAggregate{ + SyncCommitteeBits: []byte{1, 1, 1}, + SyncCommitteeSignature: []byte{1, 1, 1}, + }, + SignatureSlot: 7, + } + + updates[i] = update + + err = db.SaveLightClientUpdate(ctx, uint64(updatePeriod), ðpbv2.LightClientUpdateWithVersion{ + Version: version.Altair, + Data: update, + }) + require.NoError(t, err) + + updatePeriod++ + } + + mockBlocker := &testutil.MockBlocker{} + mockChainService := &mock.ChainService{Optimistic: true, Slot: &headSlot, State: st} + s := &Server{ + Stater: &testutil.MockStater{}, + Blocker: mockBlocker, + HeadFetcher: mockChainService, + BeaconDB: db, + } + startPeriod := slot.Sub(1).Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) + url := fmt.Sprintf("http://foo.com/?count=100&start_period=%d", startPeriod) + request := httptest.NewRequest("GET", url, nil) + writer := httptest.NewRecorder() + writer.Body = &bytes.Buffer{} + + s.GetLightClientUpdatesByRange(writer, request) + + require.Equal(t, http.StatusOK, writer.Code) + var resp structs.LightClientUpdatesByRangeResponse + err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) + require.NoError(t, err) + require.Equal(t, validUpdatesLen, len(resp.Updates)) + require.NoError(t, err) + for i, update := range updates { + if i < validUpdatesLen { + require.Equal(t, "altair", resp.Updates[i].Version) + updateJson, err := structs.LightClientUpdateFromConsensus(update) + require.NoError(t, err) + require.DeepEqual(t, updateJson, resp.Updates[i].Data) + } + } +} + +func TestLightClientHandler_GetLightClientUpdatesByRangeMissingUpdates2(t *testing.T) { + helpers.ClearCache() + ctx := context.Background() + config := params.BeaconConfig() + slot := primitives.Slot(config.AltairForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1) + + st, err := util.NewBeaconStateAltair() + require.NoError(t, err) + headSlot := slot.Add(820000) + err = st.SetSlot(headSlot) + require.NoError(t, err) + + db := setupDB(t) + + updates := make([]*ethpbv2.LightClientUpdate, 100) + + updatePeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) + + validUpdatesLen := 0 + + for i := 0; i < 100; i++ { + if i == validUpdatesLen { // skip this update + updatePeriod++ + continue + } + newSlot := slot.Add(uint64(i)) + + update := ðpbv2.LightClientUpdate{ + AttestedHeader: ðpbv2.LightClientHeaderContainer{ + Header: ðpbv2.LightClientHeaderContainer_HeaderAltair{ + HeaderAltair: ðpbv2.LightClientHeader{ + Beacon: ðpbv1.BeaconBlockHeader{ + Slot: newSlot, + ProposerIndex: 1, + ParentRoot: []byte{1, 1, 1}, + StateRoot: []byte{1, 1, 1}, + BodyRoot: []byte{1, 1, 1}, + }, + }, + }, + }, + NextSyncCommittee: ðpbv2.SyncCommittee{ + Pubkeys: nil, + AggregatePubkey: nil, + }, + NextSyncCommitteeBranch: nil, + FinalizedHeader: nil, + FinalityBranch: nil, + SyncAggregate: ðpbv1.SyncAggregate{ + SyncCommitteeBits: []byte{1, 1, 1}, + SyncCommitteeSignature: []byte{1, 1, 1}, + }, + SignatureSlot: 7, + } + + updates[i] = update + + err = db.SaveLightClientUpdate(ctx, uint64(updatePeriod), ðpbv2.LightClientUpdateWithVersion{ + Version: version.Altair, + Data: update, + }) + require.NoError(t, err) + + updatePeriod++ + } + + mockBlocker := &testutil.MockBlocker{} + mockChainService := &mock.ChainService{Optimistic: true, Slot: &headSlot, State: st} + s := &Server{ + Stater: &testutil.MockStater{}, + Blocker: mockBlocker, + HeadFetcher: mockChainService, + BeaconDB: db, + } + startPeriod := slot.Sub(1).Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)) + url := fmt.Sprintf("http://foo.com/?count=100&start_period=%d", startPeriod) + request := httptest.NewRequest("GET", url, nil) + writer := httptest.NewRecorder() + writer.Body = &bytes.Buffer{} + + s.GetLightClientUpdatesByRange(writer, request) + + require.Equal(t, http.StatusOK, writer.Code) + var resp structs.LightClientUpdatesByRangeResponse + err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) + require.NoError(t, err) + require.Equal(t, validUpdatesLen, len(resp.Updates)) + require.NoError(t, err) + for i, update := range updates { + if i < validUpdatesLen { + require.Equal(t, "altair", resp.Updates[i].Version) + updateJson, err := structs.LightClientUpdateFromConsensus(update) + require.NoError(t, err) + require.DeepEqual(t, updateJson, resp.Updates[i].Data) + } + } +} + +// TestLightClientHandler_GetLightClientFinalityUpdate tests func TestLightClientHandler_GetLightClientFinalityUpdateAltair(t *testing.T) { helpers.ClearCache() From 3bef6f5f31de58cb7aca01aa13a23eab8c912b69 Mon Sep 17 00:00:00 2001 From: Inspector-Butters Date: Mon, 14 Oct 2024 13:21:06 +0200 Subject: [PATCH 06/12] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 878a96a0b17d..a794ff648501 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,6 +58,7 @@ The format is based on Keep a Changelog, and this project adheres to Semantic Ve - Make committee aware packing the default by deprecating `--enable-committee-aware-packing`. - Moved `ConvertKzgCommitmentToVersionedHash` to the `primitives` package. - reversed the boolean return on `BatchVerifyDepositsSignatures`, from need verification, to all keys successfully verified +- Changed `GetLightClientUpdatesByRange` API to read from the DB instead of computing. ### Deprecated - `--disable-grpc-gateway` flag is deprecated due to grpc gateway removal. From aff629f6e39877a51c7a41410386c1359b17652e Mon Sep 17 00:00:00 2001 From: Inspector-Butters Date: Mon, 14 Oct 2024 13:32:23 +0200 Subject: [PATCH 07/12] remove unused functions --- beacon-chain/rpc/eth/light-client/helpers.go | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/beacon-chain/rpc/eth/light-client/helpers.go b/beacon-chain/rpc/eth/light-client/helpers.go index ce989a7d5672..da19a591fd2e 100644 --- a/beacon-chain/rpc/eth/light-client/helpers.go +++ b/beacon-chain/rpc/eth/light-client/helpers.go @@ -245,22 +245,6 @@ func createLightClientBootstrapDeneb(ctx context.Context, state state.BeaconStat return result, nil } -func newLightClientUpdateFromBeaconState( - ctx context.Context, - state state.BeaconState, - block interfaces.ReadOnlySignedBeaconBlock, - attestedState state.BeaconState, - attestedBlock interfaces.ReadOnlySignedBeaconBlock, - finalizedBlock interfaces.ReadOnlySignedBeaconBlock, -) (*structs.LightClientUpdate, error) { - result, err := lightclient.NewLightClientUpdateFromBeaconState(ctx, state, block, attestedState, attestedBlock, finalizedBlock) - if err != nil { - return nil, err - } - - return structs.LightClientUpdateFromConsensus(result) -} - func newLightClientFinalityUpdateFromBeaconState( ctx context.Context, state state.BeaconState, From 2f16a91fef9e1b5d0f637f75a194d317d1b32c31 Mon Sep 17 00:00:00 2001 From: Bastin <43618253+Inspector-Butters@users.noreply.github.com> Date: Mon, 14 Oct 2024 17:49:29 +0200 Subject: [PATCH 08/12] Update beacon-chain/rpc/eth/light-client/handlers.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: RadosÅ‚aw Kapka --- beacon-chain/rpc/eth/light-client/handlers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beacon-chain/rpc/eth/light-client/handlers.go b/beacon-chain/rpc/eth/light-client/handlers.go index fc81bcc57010..3ebc9134eb07 100644 --- a/beacon-chain/rpc/eth/light-client/handlers.go +++ b/beacon-chain/rpc/eth/light-client/handlers.go @@ -118,7 +118,7 @@ func (s *Server) GetLightClientUpdatesByRange(w http.ResponseWriter, req *http.R // get updates updatesMap, err := s.BeaconDB.LightClientUpdates(ctx, startPeriod, endPeriod) if err != nil { - httputil.HandleError(w, "could not get light client updates: "+err.Error(), http.StatusInternalServerError) + httputil.HandleError(w, "Could not get light client updates from DB: "+err.Error(), http.StatusInternalServerError) return } From 5caba412f80a50b99bf214f9e953f9ef7ec3bf96 Mon Sep 17 00:00:00 2001 From: Bastin <43618253+Inspector-Butters@users.noreply.github.com> Date: Mon, 14 Oct 2024 17:49:34 +0200 Subject: [PATCH 09/12] Update beacon-chain/rpc/eth/light-client/handlers.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: RadosÅ‚aw Kapka --- beacon-chain/rpc/eth/light-client/handlers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beacon-chain/rpc/eth/light-client/handlers.go b/beacon-chain/rpc/eth/light-client/handlers.go index 3ebc9134eb07..055352731f30 100644 --- a/beacon-chain/rpc/eth/light-client/handlers.go +++ b/beacon-chain/rpc/eth/light-client/handlers.go @@ -133,7 +133,7 @@ func (s *Server) GetLightClientUpdatesByRange(w http.ResponseWriter, req *http.R updateResponse, err := structs.LightClientUpdateResponseFromConsensus(update) if err != nil { - httputil.HandleError(w, "could not convert light client update: "+err.Error(), http.StatusInternalServerError) + httputil.HandleError(w, "Could not convert light client update: "+err.Error(), http.StatusInternalServerError) return } From 4866873d277d3483f6101d4e49104d46df005ffd Mon Sep 17 00:00:00 2001 From: Inspector-Butters Date: Mon, 14 Oct 2024 18:00:29 +0200 Subject: [PATCH 10/12] use slice instead of array --- beacon-chain/rpc/eth/light-client/handlers.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/beacon-chain/rpc/eth/light-client/handlers.go b/beacon-chain/rpc/eth/light-client/handlers.go index 055352731f30..4dbce4fc01a3 100644 --- a/beacon-chain/rpc/eth/light-client/handlers.go +++ b/beacon-chain/rpc/eth/light-client/handlers.go @@ -122,9 +122,9 @@ func (s *Server) GetLightClientUpdatesByRange(w http.ResponseWriter, req *http.R return } - updates := make([]*structs.LightClientUpdateResponse, len(updatesMap)) - updatesCount := 0 - for i, j := startPeriod, 0; i <= endPeriod; i, j = i+1, j+1 { + updates := make([]*structs.LightClientUpdateResponse, 0, len(updatesMap)) + + for i := startPeriod; i <= endPeriod; i = i + 1 { update, ok := updatesMap[i] if !ok { // Only return the first contiguous range of updates @@ -137,11 +137,10 @@ func (s *Server) GetLightClientUpdatesByRange(w http.ResponseWriter, req *http.R return } - updates[j] = updateResponse - updatesCount++ + updates = append(updates, updateResponse) } - httputil.WriteJson(w, updates[:updatesCount]) + httputil.WriteJson(w, updates) } // GetLightClientFinalityUpdate - implements https://github.com/ethereum/beacon-APIs/blob/263f4ed6c263c967f13279c7a9f5629b51c5fc55/apis/beacon/light_client/finality_update.yaml From 2c4ea0bcd0e5dd0e2b0ff7c8ce492950ac917642 Mon Sep 17 00:00:00 2001 From: Mohamad Bastin Date: Tue, 15 Oct 2024 13:50:12 +0200 Subject: [PATCH 11/12] refactor code --- beacon-chain/rpc/eth/light-client/handlers.go | 2 +- beacon-chain/rpc/eth/light-client/handlers_test.go | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/beacon-chain/rpc/eth/light-client/handlers.go b/beacon-chain/rpc/eth/light-client/handlers.go index 4dbce4fc01a3..2df55fbad624 100644 --- a/beacon-chain/rpc/eth/light-client/handlers.go +++ b/beacon-chain/rpc/eth/light-client/handlers.go @@ -124,7 +124,7 @@ func (s *Server) GetLightClientUpdatesByRange(w http.ResponseWriter, req *http.R updates := make([]*structs.LightClientUpdateResponse, 0, len(updatesMap)) - for i := startPeriod; i <= endPeriod; i = i + 1 { + for i := startPeriod; i <= endPeriod; i++ { update, ok := updatesMap[i] if !ok { // Only return the first contiguous range of updates diff --git a/beacon-chain/rpc/eth/light-client/handlers_test.go b/beacon-chain/rpc/eth/light-client/handlers_test.go index 0b23c42c7bfc..1cabfef8656e 100644 --- a/beacon-chain/rpc/eth/light-client/handlers_test.go +++ b/beacon-chain/rpc/eth/light-client/handlers_test.go @@ -302,7 +302,6 @@ func TestLightClientHandler_GetLightClientUpdatesByRangeAltair(t *testing.T) { err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) require.NoError(t, err) require.Equal(t, 1, len(resp.Updates)) - require.NoError(t, err) require.Equal(t, "altair", resp.Updates[0].Version) updateJson, err := structs.LightClientUpdateFromConsensus(update) require.NoError(t, err) @@ -399,7 +398,6 @@ func TestLightClientHandler_GetLightClientUpdatesByRangeCapella(t *testing.T) { err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) require.NoError(t, err) require.Equal(t, 1, len(resp.Updates)) - require.NoError(t, err) require.Equal(t, "capella", resp.Updates[0].Version) updateJson, err := structs.LightClientUpdateFromConsensus(update) require.NoError(t, err) @@ -496,7 +494,6 @@ func TestLightClientHandler_GetLightClientUpdatesByRangeDeneb(t *testing.T) { err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) require.NoError(t, err) require.Equal(t, 1, len(resp.Updates)) - require.NoError(t, err) require.Equal(t, "deneb", resp.Updates[0].Version) updateJson, err := structs.LightClientUpdateFromConsensus(update) require.NoError(t, err) @@ -584,7 +581,6 @@ func TestLightClientHandler_GetLightClientUpdatesByRangeMultipleAltair(t *testin err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) require.NoError(t, err) require.Equal(t, 100, len(resp.Updates)) - require.NoError(t, err) for i, update := range updates { require.Equal(t, "altair", resp.Updates[i].Version) updateJson, err := structs.LightClientUpdateFromConsensus(update) From 9dab7a99f640fa9f67f42838c5fea9584fe0b52a Mon Sep 17 00:00:00 2001 From: Inspector-Butters Date: Wed, 16 Oct 2024 17:52:35 +0200 Subject: [PATCH 12/12] refactor tests --- beacon-chain/rpc/eth/light-client/handlers_test.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/beacon-chain/rpc/eth/light-client/handlers_test.go b/beacon-chain/rpc/eth/light-client/handlers_test.go index 1cabfef8656e..7483948e1ba7 100644 --- a/beacon-chain/rpc/eth/light-client/handlers_test.go +++ b/beacon-chain/rpc/eth/light-client/handlers_test.go @@ -691,7 +691,6 @@ func TestLightClientHandler_GetLightClientUpdatesByRangeMultipleCapella(t *testi err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) require.NoError(t, err) require.Equal(t, 100, len(resp.Updates)) - require.NoError(t, err) for i, update := range updates { require.Equal(t, "capella", resp.Updates[i].Version) updateJson, err := structs.LightClientUpdateFromConsensus(update) @@ -802,7 +801,6 @@ func TestLightClientHandler_GetLightClientUpdatesByRangeMultipleDeneb(t *testing err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) require.NoError(t, err) require.Equal(t, 100, len(resp.Updates)) - require.NoError(t, err) for i, update := range updates { require.Equal(t, "deneb", resp.Updates[i].Version) updateJson, err := structs.LightClientUpdateFromConsensus(update) @@ -970,7 +968,6 @@ func TestLightClientHandler_GetLightClientUpdatesByRangeMultipleForksAltairCapel err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) require.NoError(t, err) require.Equal(t, 100, len(resp.Updates)) - require.NoError(t, err) for i, update := range updates { if i < 50 { require.Equal(t, "altair", resp.Updates[i].Version) @@ -1150,7 +1147,6 @@ func TestLightClientHandler_GetLightClientUpdatesByRangeMultipleForksCapellaDene err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) require.NoError(t, err) require.Equal(t, 100, len(resp.Updates)) - require.NoError(t, err) for i, update := range updates { if i < 50 { require.Equal(t, "capella", resp.Updates[i].Version) @@ -1244,7 +1240,6 @@ func TestLightClientHandler_GetLightClientUpdatesByRangeCountBiggerThanLimit(t * err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) require.NoError(t, err) require.Equal(t, 128, len(resp.Updates)) - require.NoError(t, err) for i, update := range updates { if i < 128 { require.Equal(t, "altair", resp.Updates[i].Version) @@ -1340,7 +1335,6 @@ func TestLightClientHandler_GetLightClientUpdatesByRangeCountBiggerThanMax(t *te err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) require.NoError(t, err) require.Equal(t, int(diffSlots), len(resp.Updates)) - require.NoError(t, err) for i, update := range updates { if i < int(diffSlots) { require.Equal(t, "altair", resp.Updates[i].Version) @@ -1432,7 +1426,6 @@ func TestLightClientHandler_GetLightClientUpdatesByRangeStartPeriodBeforeAltair( err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) require.NoError(t, err) require.Equal(t, 100, len(resp.Updates)) - require.NoError(t, err) for i, update := range updates { require.Equal(t, "altair", resp.Updates[i].Version) updateJson, err := structs.LightClientUpdateFromConsensus(update) @@ -1528,7 +1521,6 @@ func TestLightClientHandler_GetLightClientUpdatesByRangeMissingUpdates(t *testin err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) require.NoError(t, err) require.Equal(t, validUpdatesLen, len(resp.Updates)) - require.NoError(t, err) for i, update := range updates { if i < validUpdatesLen { require.Equal(t, "altair", resp.Updates[i].Version) @@ -1626,7 +1618,6 @@ func TestLightClientHandler_GetLightClientUpdatesByRangeMissingUpdates2(t *testi err = json.Unmarshal(writer.Body.Bytes(), &resp.Updates) require.NoError(t, err) require.Equal(t, validUpdatesLen, len(resp.Updates)) - require.NoError(t, err) for i, update := range updates { if i < validUpdatesLen { require.Equal(t, "altair", resp.Updates[i].Version)