Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: introduce Capella and Deneb full-node.md lc changes #14376

Merged
merged 43 commits into from
Sep 6, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
5be1c9a
feat: introduce Capella and Deneb `full-node.md` lc changes
rupam-04 Aug 22, 2024
1849d35
add switch-case and replace `[][]byte` with `[][]string`
rupam-04 Aug 23, 2024
6b93f1a
return version name in http header
rupam-04 Aug 25, 2024
2165203
populate header and use `interfaces.ReadOnlyBeaconBlock`
rupam-04 Aug 26, 2024
7387900
fix lint
rupam-04 Aug 26, 2024
b83d8a8
merge cases in switch case and replace `interfaces.ExecutionData` wit…
rupam-04 Aug 27, 2024
1aa42e4
Merge branch 'develop' into full-node-capella-deneb
rkapka Aug 29, 2024
7641787
minor fixes
rupam-04 Aug 29, 2024
78fb405
refactor `createLightClientBootstrapCapella` and `createLightClientBo…
rupam-04 Aug 30, 2024
490d15e
use lightclientheader instead of different versions
Inspector-Butters Aug 30, 2024
65b79e9
Merge branch 'full-node-capella-deneb' of https://github.com/rupam-04…
Inspector-Butters Aug 30, 2024
fbf36ce
fix failing `TestLightClientHandler_GetLightClientBootstrap` tests
rupam-04 Aug 30, 2024
8e336c0
fix lint
rupam-04 Aug 30, 2024
ad60aca
resolve conflicts
Inspector-Butters Aug 30, 2024
30b8e83
Merge branch 'full-node-capella-deneb' of https://github.com/rupam-04…
Inspector-Butters Aug 30, 2024
a99ea65
refactor handlers
Inspector-Butters Aug 30, 2024
9940aed
refactor handlers more
Inspector-Butters Aug 30, 2024
e074683
refactor handlers even more
Inspector-Butters Aug 30, 2024
259d6d5
create conversions_lightclient
Inspector-Butters Aug 30, 2024
75a2b5e
fix lint errors
Inspector-Butters Aug 30, 2024
579b26c
add deneb and capella proto headers
Inspector-Butters Aug 31, 2024
fe5bc4c
update lightclientbootstrap proto struct to capella&deneb
Inspector-Butters Aug 31, 2024
da64486
update usecases
Inspector-Butters Sep 1, 2024
ac4fc9e
update usecases
Inspector-Butters Sep 2, 2024
56e5a6f
Merge branch 'develop' into full-node-capella-deneb
Inspector-Butters Sep 2, 2024
2d60884
resolve panic in header.GetBeacon
Inspector-Butters Sep 2, 2024
892d00c
fix spacings
Inspector-Butters Sep 2, 2024
70f46dc
refactor core/lightclient.go
Inspector-Butters Sep 3, 2024
7dfa520
fix isBetterUpdate
Inspector-Butters Sep 3, 2024
25417ae
use errors.wrap instead of fmt.errorf
Inspector-Butters Sep 3, 2024
35d3154
changelog entry
Inspector-Butters Sep 3, 2024
300670d
fix lint errors
Inspector-Butters Sep 3, 2024
baf384f
fix api structs to use json rawMessage
Inspector-Butters Sep 4, 2024
d781d23
Merge branch 'develop' into full-node-capella-deneb
Inspector-Butters Sep 4, 2024
5ed956f
inline unmarshal
Inspector-Butters Sep 6, 2024
3762b93
remove redundant nil check
Inspector-Butters Sep 6, 2024
2f14fe4
revert remove redundant nil check
Inspector-Butters Sep 6, 2024
887f601
return error in newLightClientUpdateToJSON
Inspector-Butters Sep 6, 2024
c534a65
inline getExecutionData
Inspector-Butters Sep 6, 2024
bfa28bc
Merge branch 'full-node-capella-deneb' of https://github.com/rupam-04…
Inspector-Butters Sep 6, 2024
4d78491
Merge branch 'prysmaticlabs:develop' into full-node-capella-deneb
Inspector-Butters Sep 6, 2024
2dba21b
Merge branch 'full-node-capella-deneb' of https://github.com/rupam-04…
Inspector-Butters Sep 6, 2024
65c5ff8
better error handling
Inspector-Butters Sep 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions api/server/structs/endpoints_lightclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,51 @@ type LightClientHeader struct {
Beacon *BeaconBlockHeader `json:"beacon"`
}

type LightClientHeaderCapella struct {
Beacon *BeaconBlockHeader `json:"beacon"`
Execution *ExecutionPayloadHeaderCapella `json:"execution"`
ExecutionBranch [][]byte `json:"execution_branch"`
rupam-04 marked this conversation as resolved.
Show resolved Hide resolved
}

type LightClientHeaderDeneb struct {
Beacon *BeaconBlockHeader `json:"beacon"`
Execution *ExecutionPayloadHeaderDeneb `json:"execution"`
ExecutionBranch [][]byte `json:"execution_branch"`
rupam-04 marked this conversation as resolved.
Show resolved Hide resolved
}

type LightClientBootstrapResponse struct {
Version string `json:"version"`
Data *LightClientBootstrap `json:"data"`
}

type LightClientBootstrapResponseCapella struct {
Version string `json:"version"`
Data *LightClientBootstrapCapella `json:"data"`
}

type LightClientBootstrapResponseDeneb struct {
Version string `json:"version"`
Data *LightClientBootstrapDeneb `json:"data"`
}

type LightClientBootstrap struct {
Header *LightClientHeader `json:"header"`
CurrentSyncCommittee *SyncCommittee `json:"current_sync_committee"`
CurrentSyncCommitteeBranch []string `json:"current_sync_committee_branch"`
}

type LightClientBootstrapCapella struct {
Header *LightClientHeaderCapella `json:"header"`
CurrentSyncCommittee *SyncCommittee `json:"current_sync_committee"`
CurrentSyncCommitteeBranch []string `json:"current_sync_committee_branch"`
}

type LightClientBootstrapDeneb struct {
Header *LightClientHeaderDeneb `json:"header"`
CurrentSyncCommittee *SyncCommittee `json:"current_sync_committee"`
CurrentSyncCommitteeBranch []string `json:"current_sync_committee_branch"`
}

type LightClientUpdate struct {
AttestedHeader *BeaconBlockHeader `json:"attested_header"`
NextSyncCommittee *SyncCommittee `json:"next_sync_committee,omitempty"`
Expand Down
48 changes: 41 additions & 7 deletions beacon-chain/rpc/eth/light-client/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,52 @@ func (s *Server) GetLightClientBootstrap(w http.ResponseWriter, req *http.Reques
return
}

bootstrap, err := createLightClientBootstrap(ctx, state)
if err != nil {
httputil.HandleError(w, "could not get light client bootstrap: "+err.Error(), http.StatusInternalServerError)
ver := blk.Version()
if ver >= version.Deneb {
rupam-04 marked this conversation as resolved.
Show resolved Hide resolved
bootstrap, err := createLightClientBootstrapDeneb(ctx, state)
if err != nil {
httputil.HandleError(w, "could not get light client bootstrap: "+err.Error(), http.StatusInternalServerError)
return
}

response := &structs.LightClientBootstrapResponseDeneb{
Version: version.String(blk.Version()),
Data: bootstrap,
}

httputil.WriteJson(w, response)
return
}

response := &structs.LightClientBootstrapResponse{
Version: version.String(blk.Version()),
Data: bootstrap,
if ver >= version.Capella {
bootstrap, err := createLightClientBootstrapCapella(ctx, state)
if err != nil {
httputil.HandleError(w, "could not get light client bootstrap: "+err.Error(), http.StatusInternalServerError)
return
}

response := &structs.LightClientBootstrapResponseCapella{
Version: version.String(blk.Version()),
Data: bootstrap,
}
httputil.WriteJson(w, response)
return
}

httputil.WriteJson(w, response)
if ver >= version.Altair {
bootstrap, err := createLightClientBootstrap(ctx, state)
if err != nil {
httputil.HandleError(w, "could not get light client bootstrap: "+err.Error(), http.StatusInternalServerError)
return
}

response := &structs.LightClientBootstrapResponse{
Version: version.String(blk.Version()),
Data: bootstrap,
}
httputil.WriteJson(w, response)
return
}
}

// GetLightClientUpdatesByRange - implements https://github.com/ethereum/beacon-APIs/blob/263f4ed6c263c967f13279c7a9f5629b51c5fc55/apis/beacon/light_client/updates.yaml
Expand Down
106 changes: 104 additions & 2 deletions beacon-chain/rpc/eth/light-client/handlers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,58 @@ import (
"github.com/prysmaticlabs/prysm/v5/testing/util"
)

func TestLightClientHandler_GetLightClientBootstrap(t *testing.T) {
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,
}
muxVars := make(map[string]string)
muxVars["block_root"] = hexutil.Encode(r[:])
request := httptest.NewRequest("GET", "http://foo.com/", nil)
request = mux.SetURLVars(request, muxVars)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}

s.GetLightClientBootstrap(writer, request)
require.Equal(t, http.StatusOK, writer.Code)
resp := &structs.LightClientBootstrapResponse{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
require.Equal(t, "altair", resp.Version)
require.Equal(t, hexutil.Encode(header.Header.BodyRoot), resp.Data.Header.Beacon.BodyRoot)
require.NotNil(t, resp.Data)
}

func TestLightClientHandler_GetLightClientBootstrap_Capella(t *testing.T) {
helpers.ClearCache()
slot := primitives.Slot(params.BeaconConfig().AltairForkEpoch * primitives.Epoch(params.BeaconConfig().SlotsPerEpoch)).Add(1)

Expand Down Expand Up @@ -70,13 +121,64 @@ func TestLightClientHandler_GetLightClientBootstrap(t *testing.T) {

s.GetLightClientBootstrap(writer, request)
require.Equal(t, http.StatusOK, writer.Code)
resp := &structs.LightClientBootstrapResponse{}
resp := &structs.LightClientBootstrapResponseCapella{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
require.Equal(t, "capella", resp.Version)
require.Equal(t, hexutil.Encode(header.Header.BodyRoot), resp.Data.Header.Beacon.BodyRoot)
require.NotNil(t, resp.Data)
}

func TestLightClientHandler_GetLightClientBootstrap_Deneb(t *testing.T) {
helpers.ClearCache()
slot := primitives.Slot(params.BeaconConfig().AltairForkEpoch * 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,
}
muxVars := make(map[string]string)
muxVars["block_root"] = hexutil.Encode(r[:])
request := httptest.NewRequest("GET", "http://foo.com/", nil)
request = mux.SetURLVars(request, muxVars)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}

s.GetLightClientBootstrap(writer, request)
require.Equal(t, http.StatusOK, writer.Code)
resp := &structs.LightClientBootstrapResponseDeneb{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
require.Equal(t, "deneb", resp.Version)
require.Equal(t, hexutil.Encode(header.Header.BodyRoot), resp.Data.Header.Beacon.BodyRoot)
require.NotNil(t, resp.Data)
}

func TestLightClientHandler_GetLightClientUpdatesByRange(t *testing.T) {
helpers.ClearCache()
ctx := context.Background()
Expand Down
110 changes: 110 additions & 0 deletions beacon-chain/rpc/eth/light-client/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,116 @@ func createLightClientBootstrap(ctx context.Context, state state.BeaconState) (*
return result, nil
}

func createLightClientBootstrapCapella(ctx context.Context, state state.BeaconState) (*structs.LightClientBootstrapCapella, error) {
// assert compute_epoch_at_slot(state.slot) >= ALTAIR_FORK_EPOCH
rupam-04 marked this conversation as resolved.
Show resolved Hide resolved
if slots.ToEpoch(state.Slot()) < params.BeaconConfig().AltairForkEpoch {
return nil, fmt.Errorf("light client bootstrap is not supported before Altair, invalid slot %d", state.Slot())
rupam-04 marked this conversation as resolved.
Show resolved Hide resolved
}
rupam-04 marked this conversation as resolved.
Show resolved Hide resolved

// assert state.slot == state.latest_block_header.slot
latestBlockHeader := state.LatestBlockHeader()
if state.Slot() != latestBlockHeader.Slot {
return nil, fmt.Errorf("state slot %d not equal to latest block header slot %d", state.Slot(), latestBlockHeader.Slot)
}

// Prepare data
currentSyncCommittee, err := state.CurrentSyncCommittee()
if err != nil {
return nil, fmt.Errorf("could not get current sync committee: %s", err.Error())
}

committee := structs.SyncCommitteeFromConsensus(currentSyncCommittee)

currentSyncCommitteeProof, err := state.CurrentSyncCommitteeProof(ctx)
if err != nil {
return nil, fmt.Errorf("could not get current sync committee proof: %s", err.Error())
}

branch := make([]string, fieldparams.NextSyncCommitteeBranchDepth)
for i, proof := range currentSyncCommitteeProof {
branch[i] = hexutil.Encode(proof)
}

beacon := structs.BeaconBlockHeaderFromConsensus(latestBlockHeader)
if beacon == nil {
return nil, fmt.Errorf("could not get beacon block header")
}
rupam-04 marked this conversation as resolved.
Show resolved Hide resolved
header := &structs.LightClientHeaderCapella{
Beacon: beacon,
}
rupam-04 marked this conversation as resolved.
Show resolved Hide resolved

// Above shared util function won't calculate state root, so we need to do it manually
stateRoot, err := state.HashTreeRoot(ctx)
if err != nil {
return nil, fmt.Errorf("could not get state root: %s", err.Error())
}
header.Beacon.StateRoot = hexutil.Encode(stateRoot[:])

// Return result
result := &structs.LightClientBootstrapCapella{
Header: header,
CurrentSyncCommittee: committee,
CurrentSyncCommitteeBranch: branch,
}

return result, nil
}

func createLightClientBootstrapDeneb(ctx context.Context, state state.BeaconState) (*structs.LightClientBootstrapDeneb, error) {
rupam-04 marked this conversation as resolved.
Show resolved Hide resolved
// assert compute_epoch_at_slot(state.slot) >= ALTAIR_FORK_EPOCH
rupam-04 marked this conversation as resolved.
Show resolved Hide resolved
if slots.ToEpoch(state.Slot()) < params.BeaconConfig().AltairForkEpoch {
return nil, fmt.Errorf("light client bootstrap is not supported before Altair, invalid slot %d", state.Slot())
rupam-04 marked this conversation as resolved.
Show resolved Hide resolved
}
rupam-04 marked this conversation as resolved.
Show resolved Hide resolved

// assert state.slot == state.latest_block_header.slot
latestBlockHeader := state.LatestBlockHeader()
if state.Slot() != latestBlockHeader.Slot {
return nil, fmt.Errorf("state slot %d not equal to latest block header slot %d", state.Slot(), latestBlockHeader.Slot)
}

// Prepare data
currentSyncCommittee, err := state.CurrentSyncCommittee()
if err != nil {
return nil, fmt.Errorf("could not get current sync committee: %s", err.Error())
}

committee := structs.SyncCommitteeFromConsensus(currentSyncCommittee)

currentSyncCommitteeProof, err := state.CurrentSyncCommitteeProof(ctx)
if err != nil {
return nil, fmt.Errorf("could not get current sync committee proof: %s", err.Error())
}

branch := make([]string, fieldparams.NextSyncCommitteeBranchDepth)
for i, proof := range currentSyncCommitteeProof {
branch[i] = hexutil.Encode(proof)
}

beacon := structs.BeaconBlockHeaderFromConsensus(latestBlockHeader)
if beacon == nil {
return nil, fmt.Errorf("could not get beacon block header")
}
header := &structs.LightClientHeaderDeneb{
Beacon: beacon,
}
rupam-04 marked this conversation as resolved.
Show resolved Hide resolved

// Above shared util function won't calculate state root, so we need to do it manually
stateRoot, err := state.HashTreeRoot(ctx)
if err != nil {
return nil, fmt.Errorf("could not get state root: %s", err.Error())
}
header.Beacon.StateRoot = hexutil.Encode(stateRoot[:])

// Return result
result := &structs.LightClientBootstrapDeneb{
Header: header,
CurrentSyncCommittee: committee,
CurrentSyncCommitteeBranch: branch,
}

return result, nil
}

// createLightClientUpdate - implements https://github.
// com/ethereum/consensus-specs/blob/d70dcd9926a4bbe987f1b4e65c3e05bd029fcfb8/specs/altair/light-client/full-node.md#create_light_client_update
// def create_light_client_update(state: BeaconState,
Expand Down
Loading