mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-06 20:13:59 -05:00
1112 lines
38 KiB
Go
1112 lines
38 KiB
Go
package lightclient
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"math/rand"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strconv"
|
|
"testing"
|
|
|
|
"github.com/OffchainLabs/prysm/v7/api/server/structs"
|
|
"github.com/OffchainLabs/prysm/v7/async/event"
|
|
blockchainTest "github.com/OffchainLabs/prysm/v7/beacon-chain/blockchain/testing"
|
|
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/helpers"
|
|
"github.com/OffchainLabs/prysm/v7/beacon-chain/db"
|
|
dbtesting "github.com/OffchainLabs/prysm/v7/beacon-chain/db/testing"
|
|
lightclient "github.com/OffchainLabs/prysm/v7/beacon-chain/light-client"
|
|
p2ptesting "github.com/OffchainLabs/prysm/v7/beacon-chain/p2p/testing"
|
|
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
|
|
"github.com/OffchainLabs/prysm/v7/config/params"
|
|
"github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
|
|
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
|
|
light_client "github.com/OffchainLabs/prysm/v7/consensus-types/light-client"
|
|
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
|
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
|
|
pb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
|
"github.com/OffchainLabs/prysm/v7/runtime/version"
|
|
"github.com/OffchainLabs/prysm/v7/testing/require"
|
|
"github.com/OffchainLabs/prysm/v7/testing/util"
|
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
ssz "github.com/prysmaticlabs/fastssz"
|
|
"google.golang.org/protobuf/proto"
|
|
)
|
|
|
|
func TestLightClientHandler_GetLightClientBootstrap(t *testing.T) {
|
|
params.SetupTestConfigCleanup(t)
|
|
cfg := params.BeaconConfig()
|
|
cfg.AltairForkEpoch = 0
|
|
cfg.BellatrixForkEpoch = 1
|
|
cfg.CapellaForkEpoch = 2
|
|
cfg.DenebForkEpoch = 3
|
|
cfg.ElectraForkEpoch = 4
|
|
cfg.FuluForkEpoch = 5
|
|
params.OverrideBeaconConfig(cfg)
|
|
|
|
for _, testVersion := range version.All()[1:] {
|
|
if testVersion == version.Gloas {
|
|
// TODO(16027): Unskip light client tests for Gloas
|
|
continue
|
|
}
|
|
t.Run(version.String(testVersion), func(t *testing.T) {
|
|
l := util.NewTestLightClient(t, testVersion)
|
|
|
|
slot := primitives.Slot(params.BeaconConfig().VersionToForkEpochMap()[testVersion] * primitives.Epoch(params.BeaconConfig().SlotsPerEpoch)).Add(1)
|
|
blockRoot, err := l.Block.Block().HashTreeRoot()
|
|
require.NoError(t, err)
|
|
|
|
bootstrap, err := lightclient.NewLightClientBootstrapFromBeaconState(l.Ctx, slot, l.State, l.Block)
|
|
require.NoError(t, err)
|
|
|
|
db := dbtesting.SetupDB(t)
|
|
lcStore := lightclient.NewLightClientStore(&p2ptesting.FakeP2P{}, new(event.Feed), db)
|
|
require.NoError(t, err)
|
|
|
|
err = db.SaveLightClientBootstrap(l.Ctx, blockRoot[:], bootstrap)
|
|
require.NoError(t, err)
|
|
|
|
s := &Server{
|
|
LCStore: lcStore,
|
|
}
|
|
request := httptest.NewRequest("GET", "http://foo.com/", nil)
|
|
request.SetPathValue("block_root", hexutil.Encode(blockRoot[:]))
|
|
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, version.String(testVersion), resp.Version)
|
|
|
|
blockHeader, err := l.Block.Header()
|
|
require.NoError(t, err)
|
|
require.Equal(t, hexutil.Encode(blockHeader.Header.BodyRoot), respHeader.Beacon.BodyRoot)
|
|
require.Equal(t, strconv.FormatUint(uint64(blockHeader.Header.Slot), 10), respHeader.Beacon.Slot)
|
|
|
|
require.NotNil(t, resp.Data.CurrentSyncCommittee)
|
|
require.NotNil(t, resp.Data.CurrentSyncCommitteeBranch)
|
|
})
|
|
|
|
t.Run(version.String(testVersion)+"SSZ", func(t *testing.T) {
|
|
l := util.NewTestLightClient(t, testVersion)
|
|
|
|
slot := primitives.Slot(params.BeaconConfig().VersionToForkEpochMap()[testVersion] * primitives.Epoch(params.BeaconConfig().SlotsPerEpoch)).Add(1)
|
|
blockRoot, err := l.Block.Block().HashTreeRoot()
|
|
require.NoError(t, err)
|
|
|
|
bootstrap, err := lightclient.NewLightClientBootstrapFromBeaconState(l.Ctx, slot, l.State, l.Block)
|
|
require.NoError(t, err)
|
|
|
|
db := dbtesting.SetupDB(t)
|
|
lcStore := lightclient.NewLightClientStore(&p2ptesting.FakeP2P{}, new(event.Feed), db)
|
|
require.NoError(t, err)
|
|
|
|
err = db.SaveLightClientBootstrap(l.Ctx, blockRoot[:], bootstrap)
|
|
require.NoError(t, err)
|
|
|
|
s := &Server{
|
|
LCStore: lcStore,
|
|
}
|
|
request := httptest.NewRequest("GET", "http://foo.com/", nil)
|
|
request.SetPathValue("block_root", hexutil.Encode(blockRoot[:]))
|
|
request.Header.Add("Accept", "application/octet-stream")
|
|
writer := httptest.NewRecorder()
|
|
writer.Body = &bytes.Buffer{}
|
|
|
|
s.GetLightClientBootstrap(writer, request)
|
|
require.Equal(t, http.StatusOK, writer.Code)
|
|
|
|
var resp proto.Message
|
|
switch testVersion {
|
|
case version.Altair:
|
|
resp = &pb.LightClientBootstrapAltair{}
|
|
case version.Bellatrix:
|
|
resp = &pb.LightClientBootstrapAltair{}
|
|
case version.Capella:
|
|
resp = &pb.LightClientBootstrapCapella{}
|
|
case version.Deneb:
|
|
resp = &pb.LightClientBootstrapDeneb{}
|
|
case version.Electra, version.Fulu:
|
|
resp = &pb.LightClientBootstrapElectra{}
|
|
default:
|
|
t.Fatalf("Unsupported version %s", version.String(testVersion))
|
|
}
|
|
obj := resp.(ssz.Unmarshaler)
|
|
err = obj.UnmarshalSSZ(writer.Body.Bytes())
|
|
require.NoError(t, err)
|
|
|
|
bootstrapSSZ, err := bootstrap.MarshalSSZ()
|
|
require.NoError(t, err)
|
|
require.DeepSSZEqual(t, bootstrapSSZ, writer.Body.Bytes())
|
|
})
|
|
}
|
|
|
|
t.Run("no bootstrap found", func(t *testing.T) {
|
|
lcStore := lightclient.NewLightClientStore(&p2ptesting.FakeP2P{}, new(event.Feed), dbtesting.SetupDB(t))
|
|
s := &Server{
|
|
LCStore: lcStore,
|
|
}
|
|
request := httptest.NewRequest("GET", "http://foo.com/", nil)
|
|
request.SetPathValue("block_root", hexutil.Encode([]byte{0x00, 0x01, 0x02}))
|
|
writer := httptest.NewRecorder()
|
|
writer.Body = &bytes.Buffer{}
|
|
|
|
s.GetLightClientBootstrap(writer, request)
|
|
require.Equal(t, http.StatusNotFound, writer.Code)
|
|
})
|
|
}
|
|
|
|
func TestLightClientHandler_GetLightClientByRange(t *testing.T) {
|
|
helpers.ClearCache()
|
|
ctx := t.Context()
|
|
|
|
params.SetupTestConfigCleanup(t)
|
|
config := params.BeaconConfig()
|
|
config.EpochsPerSyncCommitteePeriod = 1
|
|
config.AltairForkEpoch = 0
|
|
config.BellatrixForkEpoch = 1
|
|
config.CapellaForkEpoch = 2
|
|
config.DenebForkEpoch = 3
|
|
config.ElectraForkEpoch = 4
|
|
config.FuluForkEpoch = 5
|
|
params.OverrideBeaconConfig(config)
|
|
|
|
t.Run("can save retrieve", func(t *testing.T) {
|
|
for _, testVersion := range version.All()[1:] {
|
|
if testVersion == version.Gloas {
|
|
// TODO(16027): Unskip light client tests for Gloas
|
|
continue
|
|
}
|
|
t.Run(version.String(testVersion), func(t *testing.T) {
|
|
|
|
slot := primitives.Slot(params.BeaconConfig().VersionToForkEpochMap()[testVersion] * primitives.Epoch(config.SlotsPerEpoch)).Add(1)
|
|
startPeriod := uint64(slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch)))
|
|
|
|
db := dbtesting.SetupDB(t)
|
|
|
|
updates := make([]interfaces.LightClientUpdate, 0)
|
|
for i := 1; i <= 2; i++ {
|
|
update, err := createUpdate(t, testVersion)
|
|
require.NoError(t, err)
|
|
updates = append(updates, update)
|
|
}
|
|
|
|
lcStore := lightclient.NewLightClientStore(&p2ptesting.FakeP2P{}, new(event.Feed), db)
|
|
|
|
blk := util.NewBeaconBlock()
|
|
signedBlk, err := blocks.NewSignedBeaconBlock(blk)
|
|
require.NoError(t, err)
|
|
|
|
s := &Server{
|
|
LCStore: lcStore,
|
|
HeadFetcher: &blockchainTest.ChainService{
|
|
Block: signedBlk,
|
|
},
|
|
}
|
|
|
|
saveHead(t, ctx, db)
|
|
|
|
updatePeriod := startPeriod
|
|
for _, update := range updates {
|
|
err := db.SaveLightClientUpdate(ctx, updatePeriod, update)
|
|
require.NoError(t, err)
|
|
updatePeriod++
|
|
}
|
|
|
|
t.Run("single update", func(t *testing.T) {
|
|
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.Equal(t, version.String(testVersion), resp.Updates[0].Version)
|
|
updateJson, err := structs.LightClientUpdateFromConsensus(updates[0])
|
|
require.NoError(t, err)
|
|
require.DeepEqual(t, updateJson, resp.Updates[0].Data)
|
|
})
|
|
|
|
t.Run("single update ssz", func(t *testing.T) {
|
|
url := fmt.Sprintf("http://foo.com/?count=1&start_period=%d", startPeriod)
|
|
request := httptest.NewRequest("GET", url, nil)
|
|
request.Header.Add("Accept", "application/octet-stream")
|
|
writer := httptest.NewRecorder()
|
|
writer.Body = &bytes.Buffer{}
|
|
|
|
s.GetLightClientUpdatesByRange(writer, request)
|
|
|
|
require.Equal(t, http.StatusOK, writer.Code)
|
|
var resp proto.Message
|
|
switch testVersion {
|
|
case version.Altair:
|
|
resp = &pb.LightClientUpdateAltair{}
|
|
case version.Bellatrix:
|
|
resp = &pb.LightClientUpdateAltair{}
|
|
case version.Capella:
|
|
resp = &pb.LightClientUpdateCapella{}
|
|
case version.Deneb:
|
|
resp = &pb.LightClientUpdateDeneb{}
|
|
case version.Electra, version.Fulu:
|
|
resp = &pb.LightClientUpdateElectra{}
|
|
default:
|
|
t.Fatalf("Unsupported version %s", version.String(testVersion))
|
|
}
|
|
obj := resp.(ssz.Unmarshaler)
|
|
err := obj.UnmarshalSSZ(writer.Body.Bytes()[12:]) // skip the length and fork digest prefixes
|
|
require.NoError(t, err)
|
|
|
|
ussz, err := updates[0].MarshalSSZ()
|
|
require.NoError(t, err)
|
|
require.DeepSSZEqual(t, ussz, writer.Body.Bytes()[12:])
|
|
})
|
|
|
|
t.Run("multiple updates", func(t *testing.T) {
|
|
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, 2, len(resp.Updates))
|
|
for i, update := range updates {
|
|
require.Equal(t, version.String(testVersion), resp.Updates[i].Version)
|
|
updateJson, err := structs.LightClientUpdateFromConsensus(update)
|
|
require.NoError(t, err)
|
|
require.DeepEqual(t, updateJson, resp.Updates[i].Data)
|
|
}
|
|
})
|
|
|
|
t.Run("multiple updates ssz", func(t *testing.T) {
|
|
url := fmt.Sprintf("http://foo.com/?count=100&start_period=%d", startPeriod)
|
|
request := httptest.NewRequest("GET", url, nil)
|
|
request.Header.Add("Accept", "application/octet-stream")
|
|
writer := httptest.NewRecorder()
|
|
writer.Body = &bytes.Buffer{}
|
|
|
|
s.GetLightClientUpdatesByRange(writer, request)
|
|
|
|
require.Equal(t, http.StatusOK, writer.Code)
|
|
|
|
offset := 0
|
|
for i := 0; offset < writer.Body.Len(); i++ {
|
|
updateLen := int(ssz.UnmarshallUint64(writer.Body.Bytes()[offset:offset+8]) - 4)
|
|
offset += 12
|
|
|
|
var resp proto.Message
|
|
switch testVersion {
|
|
case version.Altair:
|
|
resp = &pb.LightClientUpdateAltair{}
|
|
case version.Bellatrix:
|
|
resp = &pb.LightClientUpdateAltair{}
|
|
case version.Capella:
|
|
resp = &pb.LightClientUpdateCapella{}
|
|
case version.Deneb:
|
|
resp = &pb.LightClientUpdateDeneb{}
|
|
case version.Electra, version.Fulu:
|
|
resp = &pb.LightClientUpdateElectra{}
|
|
default:
|
|
t.Fatalf("Unsupported version %s", version.String(testVersion))
|
|
}
|
|
obj := resp.(ssz.Unmarshaler)
|
|
|
|
updateBytes := writer.Body.Bytes()[offset : offset+updateLen]
|
|
|
|
err := obj.UnmarshalSSZ(updateBytes)
|
|
require.NoError(t, err)
|
|
|
|
ussz, err := updates[i].MarshalSSZ()
|
|
require.NoError(t, err)
|
|
require.DeepSSZEqual(t, ussz, updateBytes)
|
|
|
|
offset += updateLen
|
|
}
|
|
})
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("updates from multiple forks", func(t *testing.T) {
|
|
for testVersion := version.Altair; testVersion < version.Electra; testVersion++ { // 1-2, 2-3, 3-4, 4-5
|
|
t.Run(version.String(testVersion)+"-"+version.String(testVersion+1), func(t *testing.T) {
|
|
firstForkSlot := primitives.Slot(params.BeaconConfig().VersionToForkEpochMap()[testVersion] * primitives.Epoch(config.SlotsPerEpoch)).Add(1)
|
|
secondForkSlot := primitives.Slot(params.BeaconConfig().VersionToForkEpochMap()[testVersion+1] * primitives.Epoch(config.SlotsPerEpoch)).Add(1)
|
|
|
|
db := dbtesting.SetupDB(t)
|
|
lcStore := lightclient.NewLightClientStore(&p2ptesting.FakeP2P{}, new(event.Feed), db)
|
|
|
|
blk := util.NewBeaconBlock()
|
|
signedBlk, err := blocks.NewSignedBeaconBlock(blk)
|
|
require.NoError(t, err)
|
|
|
|
s := &Server{
|
|
LCStore: lcStore,
|
|
HeadFetcher: &blockchainTest.ChainService{
|
|
Block: signedBlk,
|
|
},
|
|
}
|
|
|
|
saveHead(t, ctx, db)
|
|
|
|
updates := make([]interfaces.LightClientUpdate, 2)
|
|
|
|
updatePeriod := firstForkSlot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch))
|
|
startPeriod := updatePeriod
|
|
|
|
updates[0], err = createUpdate(t, testVersion)
|
|
require.NoError(t, err)
|
|
|
|
err = db.SaveLightClientUpdate(ctx, uint64(updatePeriod), updates[0])
|
|
require.NoError(t, err)
|
|
|
|
updatePeriod = secondForkSlot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch))
|
|
|
|
updates[1], err = createUpdate(t, testVersion+1)
|
|
require.NoError(t, err)
|
|
|
|
err = db.SaveLightClientUpdate(ctx, uint64(updatePeriod), updates[1])
|
|
require.NoError(t, err)
|
|
|
|
t.Run("json", func(t *testing.T) {
|
|
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, 2, len(resp.Updates))
|
|
for i, update := range updates {
|
|
if i < 1 {
|
|
require.Equal(t, version.String(testVersion), resp.Updates[i].Version)
|
|
} else {
|
|
require.Equal(t, version.String(testVersion+1), resp.Updates[i].Version)
|
|
}
|
|
updateJson, err := structs.LightClientUpdateFromConsensus(update)
|
|
require.NoError(t, err)
|
|
require.DeepEqual(t, updateJson, resp.Updates[i].Data)
|
|
}
|
|
})
|
|
|
|
t.Run("ssz", func(t *testing.T) {
|
|
url := fmt.Sprintf("http://foo.com/?count=100&start_period=%d", startPeriod)
|
|
request := httptest.NewRequest("GET", url, nil)
|
|
request.Header.Add("Accept", "application/octet-stream")
|
|
writer := httptest.NewRecorder()
|
|
writer.Body = &bytes.Buffer{}
|
|
|
|
s.GetLightClientUpdatesByRange(writer, request)
|
|
|
|
require.Equal(t, http.StatusOK, writer.Code)
|
|
|
|
offset := 0
|
|
updateLen := int(ssz.UnmarshallUint64(writer.Body.Bytes()[offset:offset+8]) - 4)
|
|
offset += 12
|
|
var resp proto.Message
|
|
switch testVersion {
|
|
case version.Altair:
|
|
resp = &pb.LightClientUpdateAltair{}
|
|
case version.Bellatrix:
|
|
resp = &pb.LightClientUpdateAltair{}
|
|
case version.Capella:
|
|
resp = &pb.LightClientUpdateCapella{}
|
|
case version.Deneb:
|
|
resp = &pb.LightClientUpdateDeneb{}
|
|
case version.Electra:
|
|
resp = &pb.LightClientUpdateElectra{}
|
|
default:
|
|
t.Fatalf("Unsupported version %s", version.String(testVersion))
|
|
}
|
|
obj := resp.(ssz.Unmarshaler)
|
|
err = obj.UnmarshalSSZ(writer.Body.Bytes()[offset : offset+updateLen])
|
|
require.NoError(t, err)
|
|
u0ssz, err := updates[0].MarshalSSZ()
|
|
require.NoError(t, err)
|
|
require.DeepSSZEqual(t, u0ssz, writer.Body.Bytes()[offset:offset+updateLen])
|
|
|
|
offset += updateLen
|
|
updateLen = int(ssz.UnmarshallUint64(writer.Body.Bytes()[offset:offset+8]) - 4)
|
|
offset += 12
|
|
var resp1 proto.Message
|
|
switch testVersion + 1 {
|
|
case version.Altair:
|
|
resp1 = &pb.LightClientUpdateAltair{}
|
|
case version.Bellatrix:
|
|
resp1 = &pb.LightClientUpdateAltair{}
|
|
case version.Capella:
|
|
resp1 = &pb.LightClientUpdateCapella{}
|
|
case version.Deneb:
|
|
resp1 = &pb.LightClientUpdateDeneb{}
|
|
case version.Electra:
|
|
resp1 = &pb.LightClientUpdateElectra{}
|
|
default:
|
|
t.Fatalf("Unsupported version %s", version.String(testVersion+1))
|
|
}
|
|
obj1 := resp1.(ssz.Unmarshaler)
|
|
err = obj1.UnmarshalSSZ(writer.Body.Bytes()[offset : offset+updateLen])
|
|
require.NoError(t, err)
|
|
u1ssz, err := updates[1].MarshalSSZ()
|
|
require.NoError(t, err)
|
|
require.DeepSSZEqual(t, u1ssz, writer.Body.Bytes()[offset:offset+updateLen])
|
|
})
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("count bigger than limit", func(t *testing.T) {
|
|
config.MaxRequestLightClientUpdates = 2
|
|
params.OverrideBeaconConfig(config)
|
|
slot := primitives.Slot(config.AltairForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1)
|
|
|
|
db := dbtesting.SetupDB(t)
|
|
lcStore := lightclient.NewLightClientStore(&p2ptesting.FakeP2P{}, new(event.Feed), db)
|
|
|
|
blk := util.NewBeaconBlock()
|
|
signedBlk, err := blocks.NewSignedBeaconBlock(blk)
|
|
require.NoError(t, err)
|
|
|
|
s := &Server{
|
|
LCStore: lcStore,
|
|
HeadFetcher: &blockchainTest.ChainService{
|
|
Block: signedBlk,
|
|
},
|
|
}
|
|
|
|
saveHead(t, ctx, db)
|
|
|
|
updates := make([]interfaces.LightClientUpdate, 3)
|
|
|
|
updatePeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch))
|
|
|
|
for i := range 3 {
|
|
updates[i], err = createUpdate(t, version.Altair)
|
|
require.NoError(t, err)
|
|
|
|
err = db.SaveLightClientUpdate(ctx, uint64(updatePeriod), updates[i])
|
|
require.NoError(t, err)
|
|
|
|
updatePeriod++
|
|
}
|
|
|
|
startPeriod := 0
|
|
url := fmt.Sprintf("http://foo.com/?count=4&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, 2, len(resp.Updates))
|
|
for i, update := range updates {
|
|
if i < 2 {
|
|
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)
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("count bigger than max", func(t *testing.T) {
|
|
config.MaxRequestLightClientUpdates = 2
|
|
params.OverrideBeaconConfig(config)
|
|
slot := primitives.Slot(config.AltairForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1)
|
|
|
|
db := dbtesting.SetupDB(t)
|
|
lcStore := lightclient.NewLightClientStore(&p2ptesting.FakeP2P{}, new(event.Feed), db)
|
|
|
|
blk := util.NewBeaconBlock()
|
|
signedBlk, err := blocks.NewSignedBeaconBlock(blk)
|
|
require.NoError(t, err)
|
|
|
|
s := &Server{
|
|
LCStore: lcStore,
|
|
HeadFetcher: &blockchainTest.ChainService{
|
|
Block: signedBlk,
|
|
},
|
|
}
|
|
|
|
saveHead(t, ctx, db)
|
|
|
|
updates := make([]interfaces.LightClientUpdate, 3)
|
|
|
|
updatePeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch))
|
|
|
|
for i := range 3 {
|
|
updates[i], err = createUpdate(t, version.Altair)
|
|
require.NoError(t, err)
|
|
|
|
err = db.SaveLightClientUpdate(ctx, uint64(updatePeriod), updates[i])
|
|
require.NoError(t, err)
|
|
|
|
updatePeriod++
|
|
}
|
|
|
|
startPeriod := 0
|
|
url := fmt.Sprintf("http://foo.com/?count=10&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, 2, len(resp.Updates))
|
|
for i, update := range updates {
|
|
if i < 2 {
|
|
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)
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("start period before altair", func(t *testing.T) {
|
|
config.AltairForkEpoch = 1
|
|
params.OverrideBeaconConfig(config)
|
|
|
|
db := dbtesting.SetupDB(t)
|
|
lcStore := lightclient.NewLightClientStore(&p2ptesting.FakeP2P{}, new(event.Feed), db)
|
|
|
|
s := &Server{
|
|
LCStore: lcStore,
|
|
}
|
|
|
|
startPeriod := 0
|
|
url := fmt.Sprintf("http://foo.com/?count=128&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.StatusBadRequest, writer.Code)
|
|
|
|
config.AltairForkEpoch = 0
|
|
params.OverrideBeaconConfig(config)
|
|
})
|
|
|
|
t.Run("missing updates", func(t *testing.T) {
|
|
slot := primitives.Slot(config.AltairForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1)
|
|
|
|
t.Run("missing update in the middle", func(t *testing.T) {
|
|
db := dbtesting.SetupDB(t)
|
|
lcStore := lightclient.NewLightClientStore(&p2ptesting.FakeP2P{}, new(event.Feed), db)
|
|
|
|
blk := util.NewBeaconBlock()
|
|
signedBlk, err := blocks.NewSignedBeaconBlock(blk)
|
|
require.NoError(t, err)
|
|
|
|
s := &Server{
|
|
LCStore: lcStore,
|
|
HeadFetcher: &blockchainTest.ChainService{
|
|
Block: signedBlk,
|
|
},
|
|
}
|
|
|
|
saveHead(t, ctx, db)
|
|
|
|
updates := make([]interfaces.LightClientUpdate, 3)
|
|
|
|
updatePeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch))
|
|
|
|
for i := range 3 {
|
|
if i == 1 { // skip this update
|
|
updatePeriod++
|
|
continue
|
|
}
|
|
updates[i], err = createUpdate(t, version.Altair)
|
|
require.NoError(t, err)
|
|
|
|
err = db.SaveLightClientUpdate(ctx, uint64(updatePeriod), updates[i])
|
|
require.NoError(t, err)
|
|
|
|
updatePeriod++
|
|
}
|
|
|
|
startPeriod := 0
|
|
url := fmt.Sprintf("http://foo.com/?count=10&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.Equal(t, "altair", resp.Updates[0].Version)
|
|
updateJson, err := structs.LightClientUpdateFromConsensus(updates[0])
|
|
require.NoError(t, err)
|
|
require.DeepEqual(t, updateJson, resp.Updates[0].Data)
|
|
})
|
|
|
|
t.Run("missing update at the beginning", func(t *testing.T) {
|
|
db := dbtesting.SetupDB(t)
|
|
lcStore := lightclient.NewLightClientStore(&p2ptesting.FakeP2P{}, new(event.Feed), db)
|
|
|
|
blk := util.NewBeaconBlock()
|
|
signedBlk, err := blocks.NewSignedBeaconBlock(blk)
|
|
require.NoError(t, err)
|
|
|
|
s := &Server{
|
|
LCStore: lcStore,
|
|
HeadFetcher: &blockchainTest.ChainService{
|
|
Block: signedBlk,
|
|
},
|
|
}
|
|
|
|
saveHead(t, ctx, db)
|
|
|
|
updates := make([]interfaces.LightClientUpdate, 3)
|
|
|
|
updatePeriod := slot.Div(uint64(config.EpochsPerSyncCommitteePeriod)).Div(uint64(config.SlotsPerEpoch))
|
|
|
|
for i := range 3 {
|
|
if i == 0 { // skip this update
|
|
updatePeriod++
|
|
continue
|
|
}
|
|
|
|
updates[i], err = createUpdate(t, version.Altair)
|
|
require.NoError(t, err)
|
|
|
|
err = db.SaveLightClientUpdate(ctx, uint64(updatePeriod), updates[i])
|
|
require.NoError(t, err)
|
|
|
|
updatePeriod++
|
|
}
|
|
|
|
startPeriod := 0
|
|
url := fmt.Sprintf("http://foo.com/?count=10&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, 0, len(resp.Updates))
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestLightClientHandler_GetLightClientFinalityUpdate(t *testing.T) {
|
|
helpers.ClearCache()
|
|
|
|
t.Run("no update", func(t *testing.T) {
|
|
s := &Server{LCStore: &lightclient.Store{}}
|
|
request := httptest.NewRequest("GET", "http://foo.com", nil)
|
|
writer := httptest.NewRecorder()
|
|
writer.Body = &bytes.Buffer{}
|
|
s.GetLightClientFinalityUpdate(writer, request)
|
|
require.Equal(t, http.StatusNotFound, writer.Code)
|
|
})
|
|
|
|
for _, testVersion := range version.All()[1:] {
|
|
if testVersion == version.Gloas {
|
|
// TODO(16027): Unskip light client tests for Gloas
|
|
continue
|
|
}
|
|
t.Run(version.String(testVersion), func(t *testing.T) {
|
|
ctx := t.Context()
|
|
|
|
l := util.NewTestLightClient(t, testVersion)
|
|
update, err := lightclient.NewLightClientFinalityUpdateFromBeaconState(ctx, l.State, l.Block, l.AttestedState, l.AttestedBlock, l.FinalizedBlock)
|
|
require.NoError(t, err)
|
|
|
|
lcStore := lightclient.NewLightClientStore(&p2ptesting.FakeP2P{}, new(event.Feed), dbtesting.SetupDB(t))
|
|
require.NoError(t, err)
|
|
|
|
s := &Server{
|
|
LCStore: lcStore,
|
|
}
|
|
s.LCStore.SetLastFinalityUpdate(update, false)
|
|
|
|
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)
|
|
|
|
data, err := structs.LightClientFinalityUpdateFromConsensus(update)
|
|
require.NoError(t, err)
|
|
var resp structs.LightClientFinalityUpdateResponse
|
|
err = json.Unmarshal(writer.Body.Bytes(), &resp)
|
|
require.NoError(t, err)
|
|
require.Equal(t, version.String(testVersion), resp.Version)
|
|
require.DeepEqual(t, data, resp.Data)
|
|
})
|
|
|
|
t.Run(version.String(testVersion)+" SSZ", func(t *testing.T) {
|
|
ctx := t.Context()
|
|
|
|
l := util.NewTestLightClient(t, testVersion)
|
|
update, err := lightclient.NewLightClientFinalityUpdateFromBeaconState(ctx, l.State, l.Block, l.AttestedState, l.AttestedBlock, l.FinalizedBlock)
|
|
require.NoError(t, err)
|
|
|
|
lcStore := lightclient.NewLightClientStore(&p2ptesting.FakeP2P{}, new(event.Feed), dbtesting.SetupDB(t))
|
|
require.NoError(t, err)
|
|
|
|
s := &Server{
|
|
LCStore: lcStore,
|
|
}
|
|
s.LCStore.SetLastFinalityUpdate(update, false)
|
|
|
|
request := httptest.NewRequest("GET", "http://foo.com", nil)
|
|
request.Header.Add("Accept", "application/octet-stream")
|
|
writer := httptest.NewRecorder()
|
|
writer.Body = &bytes.Buffer{}
|
|
s.GetLightClientFinalityUpdate(writer, request)
|
|
require.Equal(t, http.StatusOK, writer.Code)
|
|
|
|
var resp proto.Message
|
|
switch testVersion {
|
|
case version.Altair:
|
|
resp = &pb.LightClientFinalityUpdateAltair{}
|
|
case version.Bellatrix:
|
|
resp = &pb.LightClientFinalityUpdateAltair{}
|
|
case version.Capella:
|
|
resp = &pb.LightClientFinalityUpdateCapella{}
|
|
case version.Deneb:
|
|
resp = &pb.LightClientFinalityUpdateDeneb{}
|
|
case version.Electra, version.Fulu:
|
|
resp = &pb.LightClientFinalityUpdateElectra{}
|
|
default:
|
|
t.Fatalf("Unsupported version %s", version.String(testVersion))
|
|
}
|
|
obj := resp.(ssz.Unmarshaler)
|
|
err = obj.UnmarshalSSZ(writer.Body.Bytes())
|
|
require.NoError(t, err)
|
|
updateSSZ, err := update.MarshalSSZ()
|
|
require.NoError(t, err)
|
|
require.DeepSSZEqual(t, updateSSZ, writer.Body.Bytes())
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestLightClientHandler_GetLightClientOptimisticUpdate(t *testing.T) {
|
|
helpers.ClearCache()
|
|
|
|
t.Run("no update", func(t *testing.T) {
|
|
lcStore := lightclient.NewLightClientStore(&p2ptesting.FakeP2P{}, new(event.Feed), dbtesting.SetupDB(t))
|
|
|
|
s := &Server{
|
|
LCStore: lcStore,
|
|
}
|
|
|
|
request := httptest.NewRequest("GET", "http://foo.com", nil)
|
|
writer := httptest.NewRecorder()
|
|
writer.Body = &bytes.Buffer{}
|
|
s.GetLightClientOptimisticUpdate(writer, request)
|
|
require.Equal(t, http.StatusNotFound, writer.Code)
|
|
})
|
|
|
|
for _, testVersion := range version.All()[1:] {
|
|
if testVersion == version.Gloas {
|
|
// TODO(16027): Unskip light client tests for Gloas
|
|
continue
|
|
}
|
|
t.Run(version.String(testVersion), func(t *testing.T) {
|
|
ctx := t.Context()
|
|
l := util.NewTestLightClient(t, testVersion)
|
|
update, err := lightclient.NewLightClientOptimisticUpdateFromBeaconState(ctx, l.State, l.Block, l.AttestedState, l.AttestedBlock)
|
|
require.NoError(t, err)
|
|
|
|
lcStore := lightclient.NewLightClientStore(&p2ptesting.FakeP2P{}, new(event.Feed), dbtesting.SetupDB(t))
|
|
require.NoError(t, err)
|
|
|
|
s := &Server{
|
|
LCStore: lcStore,
|
|
}
|
|
s.LCStore.SetLastOptimisticUpdate(update, false)
|
|
|
|
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)
|
|
|
|
data, err := structs.LightClientOptimisticUpdateFromConsensus(update)
|
|
require.NoError(t, err)
|
|
var resp structs.LightClientOptimisticUpdateResponse
|
|
err = json.Unmarshal(writer.Body.Bytes(), &resp)
|
|
require.NoError(t, err)
|
|
require.Equal(t, version.String(testVersion), resp.Version)
|
|
require.DeepEqual(t, data, resp.Data)
|
|
})
|
|
|
|
t.Run(version.String(testVersion)+" SSZ", func(t *testing.T) {
|
|
ctx := t.Context()
|
|
l := util.NewTestLightClient(t, testVersion)
|
|
update, err := lightclient.NewLightClientOptimisticUpdateFromBeaconState(ctx, l.State, l.Block, l.AttestedState, l.AttestedBlock)
|
|
require.NoError(t, err)
|
|
|
|
lcStore := lightclient.NewLightClientStore(&p2ptesting.FakeP2P{}, new(event.Feed), dbtesting.SetupDB(t))
|
|
require.NoError(t, err)
|
|
|
|
s := &Server{
|
|
LCStore: lcStore,
|
|
}
|
|
s.LCStore.SetLastOptimisticUpdate(update, false)
|
|
|
|
request := httptest.NewRequest("GET", "http://foo.com", nil)
|
|
request.Header.Add("Accept", "application/octet-stream")
|
|
writer := httptest.NewRecorder()
|
|
writer.Body = &bytes.Buffer{}
|
|
s.GetLightClientOptimisticUpdate(writer, request)
|
|
require.Equal(t, http.StatusOK, writer.Code)
|
|
|
|
var resp proto.Message
|
|
switch testVersion {
|
|
case version.Altair:
|
|
resp = &pb.LightClientOptimisticUpdateAltair{}
|
|
case version.Bellatrix:
|
|
resp = &pb.LightClientOptimisticUpdateAltair{}
|
|
case version.Capella:
|
|
resp = &pb.LightClientOptimisticUpdateCapella{}
|
|
case version.Deneb:
|
|
resp = &pb.LightClientOptimisticUpdateDeneb{}
|
|
case version.Electra, version.Fulu:
|
|
resp = &pb.LightClientOptimisticUpdateDeneb{}
|
|
default:
|
|
t.Fatalf("Unsupported version %s", version.String(testVersion))
|
|
}
|
|
obj := resp.(ssz.Unmarshaler)
|
|
err = obj.UnmarshalSSZ(writer.Body.Bytes())
|
|
require.NoError(t, err)
|
|
updateSSZ, err := update.MarshalSSZ()
|
|
require.NoError(t, err)
|
|
require.DeepSSZEqual(t, updateSSZ, writer.Body.Bytes())
|
|
})
|
|
}
|
|
}
|
|
|
|
func createUpdate(t *testing.T, v int) (interfaces.LightClientUpdate, error) {
|
|
config := params.BeaconConfig()
|
|
var slot primitives.Slot
|
|
var header interfaces.LightClientHeader
|
|
var blk interfaces.ReadOnlySignedBeaconBlock
|
|
var err error
|
|
|
|
sampleRoot := make([]byte, 32)
|
|
for i := range 32 {
|
|
sampleRoot[i] = byte(i)
|
|
}
|
|
|
|
sampleExecutionBranch := make([][]byte, fieldparams.ExecutionBranchDepth)
|
|
for i := range 4 {
|
|
sampleExecutionBranch[i] = make([]byte, 32)
|
|
for j := range 32 {
|
|
sampleExecutionBranch[i][j] = byte(i + j)
|
|
}
|
|
}
|
|
|
|
switch v {
|
|
case version.Altair:
|
|
slot = primitives.Slot(config.AltairForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1)
|
|
header, err = light_client.NewWrappedHeader(&pb.LightClientHeaderAltair{
|
|
Beacon: &pb.BeaconBlockHeader{
|
|
Slot: slot,
|
|
ProposerIndex: primitives.ValidatorIndex(rand.Int()),
|
|
ParentRoot: sampleRoot,
|
|
StateRoot: sampleRoot,
|
|
BodyRoot: sampleRoot,
|
|
},
|
|
})
|
|
require.NoError(t, err)
|
|
blk, err = blocks.NewSignedBeaconBlock(util.NewBeaconBlockAltair())
|
|
require.NoError(t, err)
|
|
case version.Bellatrix:
|
|
slot = primitives.Slot(config.BellatrixForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1)
|
|
header, err = light_client.NewWrappedHeader(&pb.LightClientHeaderAltair{
|
|
Beacon: &pb.BeaconBlockHeader{
|
|
Slot: slot,
|
|
ProposerIndex: primitives.ValidatorIndex(rand.Int()),
|
|
ParentRoot: sampleRoot,
|
|
StateRoot: sampleRoot,
|
|
BodyRoot: sampleRoot,
|
|
},
|
|
})
|
|
require.NoError(t, err)
|
|
blk, err = blocks.NewSignedBeaconBlock(util.NewBeaconBlockBellatrix())
|
|
require.NoError(t, err)
|
|
case version.Capella:
|
|
slot = primitives.Slot(config.CapellaForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1)
|
|
header, err = light_client.NewWrappedHeader(&pb.LightClientHeaderCapella{
|
|
Beacon: &pb.BeaconBlockHeader{
|
|
Slot: slot,
|
|
ProposerIndex: primitives.ValidatorIndex(rand.Int()),
|
|
ParentRoot: sampleRoot,
|
|
StateRoot: sampleRoot,
|
|
BodyRoot: sampleRoot,
|
|
},
|
|
Execution: &enginev1.ExecutionPayloadHeaderCapella{
|
|
ParentHash: make([]byte, fieldparams.RootLength),
|
|
FeeRecipient: make([]byte, fieldparams.FeeRecipientLength),
|
|
StateRoot: make([]byte, fieldparams.RootLength),
|
|
ReceiptsRoot: make([]byte, fieldparams.RootLength),
|
|
LogsBloom: make([]byte, fieldparams.LogsBloomLength),
|
|
PrevRandao: make([]byte, fieldparams.RootLength),
|
|
ExtraData: make([]byte, 0),
|
|
BaseFeePerGas: make([]byte, fieldparams.RootLength),
|
|
BlockHash: make([]byte, fieldparams.RootLength),
|
|
TransactionsRoot: make([]byte, fieldparams.RootLength),
|
|
WithdrawalsRoot: make([]byte, fieldparams.RootLength),
|
|
},
|
|
ExecutionBranch: sampleExecutionBranch,
|
|
})
|
|
require.NoError(t, err)
|
|
blk, err = blocks.NewSignedBeaconBlock(util.NewBeaconBlockCapella())
|
|
require.NoError(t, err)
|
|
case version.Deneb:
|
|
slot = primitives.Slot(config.DenebForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1)
|
|
header, err = light_client.NewWrappedHeader(&pb.LightClientHeaderDeneb{
|
|
Beacon: &pb.BeaconBlockHeader{
|
|
Slot: slot,
|
|
ProposerIndex: primitives.ValidatorIndex(rand.Int()),
|
|
ParentRoot: sampleRoot,
|
|
StateRoot: sampleRoot,
|
|
BodyRoot: sampleRoot,
|
|
},
|
|
Execution: &enginev1.ExecutionPayloadHeaderDeneb{
|
|
ParentHash: make([]byte, fieldparams.RootLength),
|
|
FeeRecipient: make([]byte, fieldparams.FeeRecipientLength),
|
|
StateRoot: make([]byte, fieldparams.RootLength),
|
|
ReceiptsRoot: make([]byte, fieldparams.RootLength),
|
|
LogsBloom: make([]byte, fieldparams.LogsBloomLength),
|
|
PrevRandao: make([]byte, fieldparams.RootLength),
|
|
ExtraData: make([]byte, 0),
|
|
BaseFeePerGas: make([]byte, fieldparams.RootLength),
|
|
BlockHash: make([]byte, fieldparams.RootLength),
|
|
TransactionsRoot: make([]byte, fieldparams.RootLength),
|
|
WithdrawalsRoot: make([]byte, fieldparams.RootLength),
|
|
},
|
|
ExecutionBranch: sampleExecutionBranch,
|
|
})
|
|
require.NoError(t, err)
|
|
blk, err = blocks.NewSignedBeaconBlock(util.NewBeaconBlockDeneb())
|
|
require.NoError(t, err)
|
|
case version.Electra:
|
|
slot = primitives.Slot(config.ElectraForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1)
|
|
header, err = light_client.NewWrappedHeader(&pb.LightClientHeaderDeneb{
|
|
Beacon: &pb.BeaconBlockHeader{
|
|
Slot: slot,
|
|
ProposerIndex: primitives.ValidatorIndex(rand.Int()),
|
|
ParentRoot: sampleRoot,
|
|
StateRoot: sampleRoot,
|
|
BodyRoot: sampleRoot,
|
|
},
|
|
Execution: &enginev1.ExecutionPayloadHeaderDeneb{
|
|
ParentHash: make([]byte, fieldparams.RootLength),
|
|
FeeRecipient: make([]byte, fieldparams.FeeRecipientLength),
|
|
StateRoot: make([]byte, fieldparams.RootLength),
|
|
ReceiptsRoot: make([]byte, fieldparams.RootLength),
|
|
LogsBloom: make([]byte, fieldparams.LogsBloomLength),
|
|
PrevRandao: make([]byte, fieldparams.RootLength),
|
|
ExtraData: make([]byte, 0),
|
|
BaseFeePerGas: make([]byte, fieldparams.RootLength),
|
|
BlockHash: make([]byte, fieldparams.RootLength),
|
|
TransactionsRoot: make([]byte, fieldparams.RootLength),
|
|
WithdrawalsRoot: make([]byte, fieldparams.RootLength),
|
|
},
|
|
ExecutionBranch: sampleExecutionBranch,
|
|
})
|
|
require.NoError(t, err)
|
|
blk, err = blocks.NewSignedBeaconBlock(util.NewBeaconBlockElectra())
|
|
require.NoError(t, err)
|
|
case version.Fulu:
|
|
slot = primitives.Slot(config.FuluForkEpoch * primitives.Epoch(config.SlotsPerEpoch)).Add(1)
|
|
header, err = light_client.NewWrappedHeader(&pb.LightClientHeaderDeneb{
|
|
Beacon: &pb.BeaconBlockHeader{
|
|
Slot: slot,
|
|
ProposerIndex: primitives.ValidatorIndex(rand.Int()),
|
|
ParentRoot: sampleRoot,
|
|
StateRoot: sampleRoot,
|
|
BodyRoot: sampleRoot,
|
|
},
|
|
Execution: &enginev1.ExecutionPayloadHeaderDeneb{
|
|
ParentHash: make([]byte, fieldparams.RootLength),
|
|
FeeRecipient: make([]byte, fieldparams.FeeRecipientLength),
|
|
StateRoot: make([]byte, fieldparams.RootLength),
|
|
ReceiptsRoot: make([]byte, fieldparams.RootLength),
|
|
LogsBloom: make([]byte, fieldparams.LogsBloomLength),
|
|
PrevRandao: make([]byte, fieldparams.RootLength),
|
|
ExtraData: make([]byte, 0),
|
|
BaseFeePerGas: make([]byte, fieldparams.RootLength),
|
|
BlockHash: make([]byte, fieldparams.RootLength),
|
|
TransactionsRoot: make([]byte, fieldparams.RootLength),
|
|
WithdrawalsRoot: make([]byte, fieldparams.RootLength),
|
|
},
|
|
ExecutionBranch: sampleExecutionBranch,
|
|
})
|
|
require.NoError(t, err)
|
|
blk, err = blocks.NewSignedBeaconBlock(util.NewBeaconBlockFulu())
|
|
require.NoError(t, err)
|
|
default:
|
|
return nil, fmt.Errorf("unsupported version %s", version.String(v))
|
|
}
|
|
|
|
update, err := lightclient.CreateDefaultLightClientUpdate(blk)
|
|
require.NoError(t, err)
|
|
update.SetSignatureSlot(slot - 1)
|
|
syncCommitteeBits := make([]byte, 64)
|
|
syncCommitteeSignature := make([]byte, 96)
|
|
update.SetSyncAggregate(&pb.SyncAggregate{
|
|
SyncCommitteeBits: syncCommitteeBits,
|
|
SyncCommitteeSignature: syncCommitteeSignature,
|
|
})
|
|
|
|
require.NoError(t, update.SetAttestedHeader(header))
|
|
require.NoError(t, update.SetFinalizedHeader(header))
|
|
|
|
return update, nil
|
|
}
|
|
|
|
func saveHead(t *testing.T, ctx context.Context, d db.Database) {
|
|
blk := util.NewBeaconBlock()
|
|
blkRoot, err := blk.Block.HashTreeRoot()
|
|
require.NoError(t, err)
|
|
util.SaveBlock(t, ctx, d, blk)
|
|
st, err := util.NewBeaconState()
|
|
require.NoError(t, err)
|
|
require.NoError(t, d.SaveState(ctx, st, blkRoot))
|
|
require.NoError(t, d.SaveHeadBlockRoot(ctx, blkRoot))
|
|
}
|