mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-08 21:08:10 -05:00
* Replaced mux with http.Servmux * updated change log * james suggestions * lint * lint fix 2 * passed middlewares from validatorclient * gazelle fix * fixed issue * added middlewares field to rpc config * suggestions applied * updated godoc * fixed TestCors * refactor * godoc added * cli code removed and lint fixed --------- Co-authored-by: james-prysm <90280386+james-prysm@users.noreply.github.com>
2009 lines
64 KiB
Go
2009 lines
64 KiB
Go
package lightclient
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
"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/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"
|
|
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
|
|
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
|
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
|
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
|
)
|
|
|
|
func TestLightClientHandler_GetLightClientBootstrap_Altair(t *testing.T) {
|
|
helpers.ClearCache()
|
|
slot := primitives.Slot(params.BeaconConfig().AltairForkEpoch * primitives.Epoch(params.BeaconConfig().SlotsPerEpoch)).Add(1)
|
|
|
|
b := util.NewBeaconBlockAltair()
|
|
b.Block.StateRoot = bytesutil.PadTo([]byte("foo"), 32)
|
|
b.Block.Slot = slot
|
|
|
|
signedBlock, err := blocks.NewSignedBeaconBlock(b)
|
|
|
|
require.NoError(t, err)
|
|
header, err := signedBlock.Header()
|
|
require.NoError(t, err)
|
|
|
|
r, err := b.Block.HashTreeRoot()
|
|
require.NoError(t, err)
|
|
|
|
bs, err := util.NewBeaconStateAltair(func(state *ethpb.BeaconStateAltair) error {
|
|
state.BlockRoots[0] = r[:]
|
|
return nil
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
require.NoError(t, bs.SetSlot(slot))
|
|
require.NoError(t, bs.SetLatestBlockHeader(header.Header))
|
|
|
|
mockBlocker := &testutil.MockBlocker{BlockToReturn: signedBlock}
|
|
mockChainService := &mock.ChainService{Optimistic: true, Slot: &slot}
|
|
s := &Server{
|
|
Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{
|
|
slot: bs,
|
|
}},
|
|
Blocker: mockBlocker,
|
|
HeadFetcher: mockChainService,
|
|
}
|
|
request := httptest.NewRequest("GET", "http://foo.com/", nil)
|
|
request.SetPathValue("block_root", hexutil.Encode(r[:]))
|
|
writer := httptest.NewRecorder()
|
|
writer.Body = &bytes.Buffer{}
|
|
|
|
s.GetLightClientBootstrap(writer, request)
|
|
require.Equal(t, http.StatusOK, writer.Code)
|
|
var resp structs.LightClientBootstrapResponse
|
|
err = json.Unmarshal(writer.Body.Bytes(), &resp)
|
|
require.NoError(t, err)
|
|
var respHeader structs.LightClientHeader
|
|
err = json.Unmarshal(resp.Data.Header, &respHeader)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "altair", resp.Version)
|
|
require.Equal(t, hexutil.Encode(header.Header.BodyRoot), respHeader.Beacon.BodyRoot)
|
|
require.NotNil(t, resp.Data)
|
|
}
|
|
|
|
func TestLightClientHandler_GetLightClientBootstrap_Capella(t *testing.T) {
|
|
helpers.ClearCache()
|
|
slot := primitives.Slot(params.BeaconConfig().CapellaForkEpoch * primitives.Epoch(params.BeaconConfig().SlotsPerEpoch)).Add(1)
|
|
|
|
b := util.NewBeaconBlockCapella()
|
|
b.Block.StateRoot = bytesutil.PadTo([]byte("foo"), 32)
|
|
b.Block.Slot = slot
|
|
|
|
signedBlock, err := blocks.NewSignedBeaconBlock(b)
|
|
|
|
require.NoError(t, err)
|
|
header, err := signedBlock.Header()
|
|
require.NoError(t, err)
|
|
|
|
r, err := b.Block.HashTreeRoot()
|
|
require.NoError(t, err)
|
|
|
|
bs, err := util.NewBeaconStateCapella(func(state *ethpb.BeaconStateCapella) error {
|
|
state.BlockRoots[0] = r[:]
|
|
return nil
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
require.NoError(t, bs.SetSlot(slot))
|
|
require.NoError(t, bs.SetLatestBlockHeader(header.Header))
|
|
|
|
mockBlocker := &testutil.MockBlocker{BlockToReturn: signedBlock}
|
|
mockChainService := &mock.ChainService{Optimistic: true, Slot: &slot}
|
|
s := &Server{
|
|
Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{
|
|
slot: bs,
|
|
}},
|
|
Blocker: mockBlocker,
|
|
HeadFetcher: mockChainService,
|
|
}
|
|
request := httptest.NewRequest("GET", "http://foo.com/", nil)
|
|
request.SetPathValue("block_root", hexutil.Encode(r[:]))
|
|
writer := httptest.NewRecorder()
|
|
writer.Body = &bytes.Buffer{}
|
|
|
|
s.GetLightClientBootstrap(writer, request)
|
|
require.Equal(t, http.StatusOK, writer.Code)
|
|
var resp structs.LightClientBootstrapResponse
|
|
err = json.Unmarshal(writer.Body.Bytes(), &resp)
|
|
require.NoError(t, err)
|
|
var respHeader structs.LightClientHeaderCapella
|
|
err = json.Unmarshal(resp.Data.Header, &respHeader)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "capella", resp.Version)
|
|
require.Equal(t, hexutil.Encode(header.Header.BodyRoot), respHeader.Beacon.BodyRoot)
|
|
require.NotNil(t, resp.Data)
|
|
}
|
|
|
|
func TestLightClientHandler_GetLightClientBootstrap_Deneb(t *testing.T) {
|
|
helpers.ClearCache()
|
|
slot := primitives.Slot(params.BeaconConfig().DenebForkEpoch * primitives.Epoch(params.BeaconConfig().SlotsPerEpoch)).Add(1)
|
|
|
|
b := util.NewBeaconBlockDeneb()
|
|
b.Block.StateRoot = bytesutil.PadTo([]byte("foo"), 32)
|
|
b.Block.Slot = slot
|
|
|
|
signedBlock, err := blocks.NewSignedBeaconBlock(b)
|
|
|
|
require.NoError(t, err)
|
|
header, err := signedBlock.Header()
|
|
require.NoError(t, err)
|
|
|
|
r, err := b.Block.HashTreeRoot()
|
|
require.NoError(t, err)
|
|
|
|
bs, err := util.NewBeaconStateDeneb(func(state *ethpb.BeaconStateDeneb) error {
|
|
state.BlockRoots[0] = r[:]
|
|
return nil
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
require.NoError(t, bs.SetSlot(slot))
|
|
require.NoError(t, bs.SetLatestBlockHeader(header.Header))
|
|
|
|
mockBlocker := &testutil.MockBlocker{BlockToReturn: signedBlock}
|
|
mockChainService := &mock.ChainService{Optimistic: true, Slot: &slot}
|
|
s := &Server{
|
|
Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{
|
|
slot: bs,
|
|
}},
|
|
Blocker: mockBlocker,
|
|
HeadFetcher: mockChainService,
|
|
}
|
|
request := httptest.NewRequest("GET", "http://foo.com/", nil)
|
|
request.SetPathValue("block_root", hexutil.Encode(r[:]))
|
|
writer := httptest.NewRecorder()
|
|
writer.Body = &bytes.Buffer{}
|
|
|
|
s.GetLightClientBootstrap(writer, request)
|
|
require.Equal(t, http.StatusOK, writer.Code)
|
|
var resp structs.LightClientBootstrapResponse
|
|
err = json.Unmarshal(writer.Body.Bytes(), &resp)
|
|
require.NoError(t, err)
|
|
var respHeader structs.LightClientHeaderDeneb
|
|
err = json.Unmarshal(resp.Data.Header, &respHeader)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "deneb", resp.Version)
|
|
require.Equal(t, hexutil.Encode(header.Header.BodyRoot), respHeader.Beacon.BodyRoot)
|
|
require.NotNil(t, resp.Data)
|
|
}
|
|
|
|
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)
|
|
|
|
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)
|
|
|
|
// 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()
|
|
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)
|
|
|
|
require.NoError(t, attestedState.SetFinalizedCheckpoint(ðpb.Checkpoint{
|
|
Epoch: config.AltairForkEpoch - 10,
|
|
Root: make([]byte, 32),
|
|
}))
|
|
|
|
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, FinalizedRoots: map[[32]byte]bool{
|
|
root: true,
|
|
}}
|
|
s := &Server{
|
|
Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{
|
|
slot.Sub(1): attestedState,
|
|
slot: st,
|
|
}},
|
|
Blocker: mockBlocker,
|
|
HeadFetcher: mockChainService,
|
|
}
|
|
request := httptest.NewRequest("GET", "http://foo.com", nil)
|
|
writer := httptest.NewRecorder()
|
|
writer.Body = &bytes.Buffer{}
|
|
|
|
s.GetLightClientFinalityUpdate(writer, request)
|
|
|
|
require.Equal(t, http.StatusOK, writer.Code)
|
|
var resp structs.LightClientUpdateWithVersion
|
|
err = json.Unmarshal(writer.Body.Bytes(), &resp)
|
|
require.NoError(t, err)
|
|
var respHeader structs.LightClientHeader
|
|
err = json.Unmarshal(resp.Data.AttestedHeader, &respHeader)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "altair", resp.Version)
|
|
require.Equal(t, hexutil.Encode(attestedHeader.BodyRoot), respHeader.Beacon.BodyRoot)
|
|
require.NotNil(t, resp.Data)
|
|
}
|
|
|
|
func TestLightClientHandler_GetLightClientFinalityUpdateCapella(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)
|
|
|
|
require.NoError(t, attestedState.SetFinalizedCheckpoint(ðpb.Checkpoint{
|
|
Epoch: config.AltairForkEpoch - 10,
|
|
Root: make([]byte, 32),
|
|
}))
|
|
|
|
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, FinalizedRoots: map[[32]byte]bool{
|
|
root: true,
|
|
}}
|
|
s := &Server{
|
|
Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{
|
|
slot.Sub(1): attestedState,
|
|
slot: st,
|
|
}},
|
|
Blocker: mockBlocker,
|
|
HeadFetcher: mockChainService,
|
|
}
|
|
request := httptest.NewRequest("GET", "http://foo.com", nil)
|
|
writer := httptest.NewRecorder()
|
|
writer.Body = &bytes.Buffer{}
|
|
|
|
s.GetLightClientFinalityUpdate(writer, request)
|
|
|
|
require.Equal(t, http.StatusOK, writer.Code)
|
|
var resp structs.LightClientUpdateWithVersion
|
|
err = json.Unmarshal(writer.Body.Bytes(), &resp)
|
|
require.NoError(t, err)
|
|
var respHeader structs.LightClientHeader
|
|
err = json.Unmarshal(resp.Data.AttestedHeader, &respHeader)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "capella", resp.Version)
|
|
require.Equal(t, hexutil.Encode(attestedHeader.BodyRoot), respHeader.Beacon.BodyRoot)
|
|
require.NotNil(t, resp.Data)
|
|
}
|
|
|
|
func TestLightClientHandler_GetLightClientFinalityUpdateDeneb(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)
|
|
|
|
require.NoError(t, attestedState.SetFinalizedCheckpoint(ðpb.Checkpoint{
|
|
Epoch: config.AltairForkEpoch - 10,
|
|
Root: make([]byte, 32),
|
|
}))
|
|
|
|
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, FinalizedRoots: map[[32]byte]bool{
|
|
root: true,
|
|
}}
|
|
s := &Server{
|
|
Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{
|
|
slot.Sub(1): attestedState,
|
|
slot: st,
|
|
}},
|
|
Blocker: mockBlocker,
|
|
HeadFetcher: mockChainService,
|
|
}
|
|
request := httptest.NewRequest("GET", "http://foo.com", nil)
|
|
writer := httptest.NewRecorder()
|
|
writer.Body = &bytes.Buffer{}
|
|
|
|
s.GetLightClientFinalityUpdate(writer, request)
|
|
|
|
require.Equal(t, http.StatusOK, writer.Code)
|
|
var resp structs.LightClientUpdateWithVersion
|
|
err = json.Unmarshal(writer.Body.Bytes(), &resp)
|
|
require.NoError(t, err)
|
|
var respHeader structs.LightClientHeaderDeneb
|
|
err = json.Unmarshal(resp.Data.AttestedHeader, &respHeader)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "deneb", resp.Version)
|
|
require.Equal(t, hexutil.Encode(attestedHeader.BodyRoot), respHeader.Beacon.BodyRoot)
|
|
require.NotNil(t, resp.Data)
|
|
}
|
|
|
|
func TestLightClientHandler_GetLightClientOptimisticUpdateAltair(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)
|
|
|
|
require.NoError(t, attestedState.SetFinalizedCheckpoint(ðpb.Checkpoint{
|
|
Epoch: config.AltairForkEpoch - 10,
|
|
Root: make([]byte, 32),
|
|
}))
|
|
|
|
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, FinalizedRoots: map[[32]byte]bool{
|
|
root: true,
|
|
}}
|
|
s := &Server{
|
|
Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{
|
|
slot.Sub(1): attestedState,
|
|
slot: st,
|
|
}},
|
|
Blocker: mockBlocker,
|
|
HeadFetcher: mockChainService,
|
|
}
|
|
request := httptest.NewRequest("GET", "http://foo.com", nil)
|
|
writer := httptest.NewRecorder()
|
|
writer.Body = &bytes.Buffer{}
|
|
|
|
s.GetLightClientOptimisticUpdate(writer, request)
|
|
|
|
require.Equal(t, http.StatusOK, writer.Code)
|
|
var resp structs.LightClientUpdateWithVersion
|
|
err = json.Unmarshal(writer.Body.Bytes(), &resp)
|
|
require.NoError(t, err)
|
|
var respHeader structs.LightClientHeader
|
|
err = json.Unmarshal(resp.Data.AttestedHeader, &respHeader)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "altair", resp.Version)
|
|
require.Equal(t, hexutil.Encode(attestedHeader.BodyRoot), respHeader.Beacon.BodyRoot)
|
|
require.NotNil(t, resp.Data)
|
|
}
|
|
|
|
func TestLightClientHandler_GetLightClientOptimisticUpdateCapella(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)
|
|
|
|
require.NoError(t, attestedState.SetFinalizedCheckpoint(ðpb.Checkpoint{
|
|
Epoch: config.AltairForkEpoch - 10,
|
|
Root: make([]byte, 32),
|
|
}))
|
|
|
|
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, FinalizedRoots: map[[32]byte]bool{
|
|
root: true,
|
|
}}
|
|
s := &Server{
|
|
Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{
|
|
slot.Sub(1): attestedState,
|
|
slot: st,
|
|
}},
|
|
Blocker: mockBlocker,
|
|
HeadFetcher: mockChainService,
|
|
}
|
|
request := httptest.NewRequest("GET", "http://foo.com", nil)
|
|
writer := httptest.NewRecorder()
|
|
writer.Body = &bytes.Buffer{}
|
|
|
|
s.GetLightClientOptimisticUpdate(writer, request)
|
|
|
|
require.Equal(t, http.StatusOK, writer.Code)
|
|
var resp structs.LightClientUpdateWithVersion
|
|
err = json.Unmarshal(writer.Body.Bytes(), &resp)
|
|
require.NoError(t, err)
|
|
var respHeader structs.LightClientHeaderCapella
|
|
err = json.Unmarshal(resp.Data.AttestedHeader, &respHeader)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "capella", resp.Version)
|
|
require.Equal(t, hexutil.Encode(attestedHeader.BodyRoot), respHeader.Beacon.BodyRoot)
|
|
require.NotNil(t, resp.Data)
|
|
}
|
|
|
|
func TestLightClientHandler_GetLightClientOptimisticUpdateDeneb(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)
|
|
|
|
require.NoError(t, attestedState.SetFinalizedCheckpoint(ðpb.Checkpoint{
|
|
Epoch: config.AltairForkEpoch - 10,
|
|
Root: make([]byte, 32),
|
|
}))
|
|
|
|
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, FinalizedRoots: map[[32]byte]bool{
|
|
root: true,
|
|
}}
|
|
s := &Server{
|
|
Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{
|
|
slot.Sub(1): attestedState,
|
|
slot: st,
|
|
}},
|
|
Blocker: mockBlocker,
|
|
HeadFetcher: mockChainService,
|
|
}
|
|
request := httptest.NewRequest("GET", "http://foo.com", nil)
|
|
writer := httptest.NewRecorder()
|
|
writer.Body = &bytes.Buffer{}
|
|
|
|
s.GetLightClientOptimisticUpdate(writer, request)
|
|
|
|
require.Equal(t, http.StatusOK, writer.Code)
|
|
var resp structs.LightClientUpdateWithVersion
|
|
err = json.Unmarshal(writer.Body.Bytes(), &resp)
|
|
require.NoError(t, err)
|
|
var respHeader structs.LightClientHeaderDeneb
|
|
err = json.Unmarshal(resp.Data.AttestedHeader, &respHeader)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "deneb", resp.Version)
|
|
require.Equal(t, hexutil.Encode(attestedHeader.BodyRoot), respHeader.Beacon.BodyRoot)
|
|
require.NotNil(t, resp.Data)
|
|
}
|
|
|
|
func TestLightClientHandler_GetLightClientEventBlock(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)
|
|
|
|
require.NoError(t, attestedState.SetFinalizedCheckpoint(ðpb.Checkpoint{
|
|
Epoch: config.AltairForkEpoch - 10,
|
|
Root: make([]byte, 32),
|
|
}))
|
|
|
|
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, FinalizedRoots: map[[32]byte]bool{
|
|
root: true,
|
|
}}
|
|
s := &Server{
|
|
Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{
|
|
slot.Sub(1): attestedState,
|
|
slot: st,
|
|
}},
|
|
Blocker: mockBlocker,
|
|
HeadFetcher: mockChainService,
|
|
}
|
|
|
|
minSignaturesRequired := uint64(100)
|
|
eventBlock, err := s.getLightClientEventBlock(ctx, minSignaturesRequired)
|
|
|
|
require.NoError(t, err)
|
|
require.NotNil(t, eventBlock)
|
|
require.Equal(t, slot, eventBlock.Block().Slot())
|
|
syncAggregate, err := eventBlock.Block().Body().SyncAggregate()
|
|
require.NoError(t, err)
|
|
require.Equal(t, true, syncAggregate.SyncCommitteeBits.Count() >= minSignaturesRequired)
|
|
}
|
|
|
|
func TestLightClientHandler_GetLightClientEventBlock_NeedFetchParent(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)
|
|
|
|
require.NoError(t, attestedState.SetFinalizedCheckpoint(ðpb.Checkpoint{
|
|
Epoch: config.AltairForkEpoch - 10,
|
|
Root: make([]byte, 32),
|
|
}))
|
|
|
|
parent := util.NewBeaconBlockCapella()
|
|
parent.Block.Slot = slot.Sub(1)
|
|
for i := uint64(0); i < config.SyncCommitteeSize; i++ {
|
|
parent.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true)
|
|
}
|
|
|
|
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 < 10; 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, FinalizedRoots: map[[32]byte]bool{
|
|
root: true,
|
|
}}
|
|
s := &Server{
|
|
Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{
|
|
slot.Sub(1): attestedState,
|
|
slot: st,
|
|
}},
|
|
Blocker: mockBlocker,
|
|
HeadFetcher: mockChainService,
|
|
}
|
|
|
|
minSignaturesRequired := uint64(100)
|
|
eventBlock, err := s.getLightClientEventBlock(ctx, minSignaturesRequired)
|
|
|
|
require.NoError(t, err)
|
|
require.NotNil(t, eventBlock)
|
|
syncAggregate, err := eventBlock.Block().Body().SyncAggregate()
|
|
require.NoError(t, err)
|
|
require.Equal(t, true, syncAggregate.SyncCommitteeBits.Count() >= minSignaturesRequired)
|
|
require.Equal(t, slot-1, eventBlock.Block().Slot())
|
|
}
|