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

core/validatorapi: validator api builder proposer #847

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions core/validatorapi/eth2types.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ type proposeBlockResponseBellatrix struct {
Data *bellatrix.BeaconBlock `json:"data"`
}

type proposeBlindedBlockResponseBellatrix struct {
Version string `json:"version"`
Data *eth2v1.BlindedBeaconBlock `json:"data"`
}

type validatorsResponse struct {
Data []v1Validator `json:"data"`
}
Expand Down
69 changes: 69 additions & 0 deletions core/validatorapi/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"time"

eth2client "github.com/attestantio/go-eth2-client"
eth2api "github.com/attestantio/go-eth2-client/api"
eth2v1 "github.com/attestantio/go-eth2-client/api/v1"
"github.com/attestantio/go-eth2-client/spec"
"github.com/attestantio/go-eth2-client/spec/altair"
Expand All @@ -57,6 +58,8 @@ type Handler interface {
eth2client.AttesterDutiesProvider
eth2client.BeaconBlockProposalProvider
eth2client.BeaconBlockSubmitter
eth2client.BlindedBeaconBlockProposalProvider
eth2client.BlindedBeaconBlockSubmitter
eth2client.ProposerDutiesProvider
eth2client.ValidatorsProvider
eth2client.VoluntaryExitSubmitter
Expand Down Expand Up @@ -113,6 +116,16 @@ func NewRouter(h Handler, eth2Cl eth2client.Service) (*mux.Router, error) {
Path: "/eth/v1/beacon/blocks",
Handler: submitBlock(h),
},
{
Name: "propose_blinded_block",
Path: "/eth/v1/validator/blinded_blocks/{slot}",
Handler: proposeBlindedBlock(h),
},
{
Name: "submit_blinded_block",
Path: "/eth/v1/beacon/blinded_blocks",
Handler: submitBlindedBlock(h),
},
{
Name: "submit_voluntary_exit",
Path: "/eth/v1/beacon/pool/voluntary_exits",
Expand Down Expand Up @@ -391,6 +404,45 @@ func proposeBlock(p eth2client.BeaconBlockProposalProvider) handlerFunc {
}
}

// proposeBlindedBlock receives the randao from the validator and returns the unsigned BlindedBeaconBlock.
func proposeBlindedBlock(p eth2client.BlindedBeaconBlockProposalProvider) handlerFunc {
return func(ctx context.Context, params map[string]string, query url.Values, body []byte) (interface{}, error) {
slot, err := uintParam(params, "slot")
if err != nil {
return nil, err
}

var randao eth2p0.BLSSignature
b, err := hexQuery(query, "randao_reveal")
if err != nil {
return nil, err
}
if len(b) != len(randao) {
return nil, errors.New("input randao_reveal has wrong length")
}
copy(randao[:], b)

block, err := p.BlindedBeaconBlockProposal(ctx, eth2p0.Slot(slot), randao, nil)
if err != nil {
return nil, err
}

switch block.Version {
case spec.DataVersionBellatrix:
if block.Bellatrix == nil {
return 0, errors.New("no bellatrix block")
}

return proposeBlindedBlockResponseBellatrix{
Version: "BELLATRIX",
Data: block.Bellatrix,
}, nil
default:
return 0, errors.New("invalid block")
}
}
}

func submitBlock(p eth2client.BeaconBlockSubmitter) handlerFunc {
return func(ctx context.Context, params map[string]string, query url.Values, body []byte) (interface{}, error) {
bellatrixBlock := new(bellatrix.SignedBeaconBlock)
Expand Down Expand Up @@ -430,6 +482,23 @@ func submitBlock(p eth2client.BeaconBlockSubmitter) handlerFunc {
}
}

func submitBlindedBlock(p eth2client.BlindedBeaconBlockSubmitter) handlerFunc {
return func(ctx context.Context, params map[string]string, query url.Values, body []byte) (interface{}, error) {
bellatrixBlock := new(eth2v1.SignedBlindedBeaconBlock)
err := bellatrixBlock.UnmarshalJSON(body)
if err == nil {
block := &eth2api.VersionedSignedBlindedBeaconBlock{
Version: spec.DataVersionBellatrix,
Bellatrix: bellatrixBlock,
}

return nil, p.SubmitBlindedBeaconBlock(ctx, block)
}

return nil, errors.New("invalid block")
}
}

// submitExit returns a handler function for the exit submitter endpoint.
func submitExit(p eth2client.VoluntaryExitSubmitter) handlerFunc {
return func(ctx context.Context, _ map[string]string, _ url.Values, body []byte) (interface{}, error) {
Expand Down
72 changes: 63 additions & 9 deletions core/validatorapi/router_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"strings"
"testing"

eth2api "github.com/attestantio/go-eth2-client/api"
eth2v1 "github.com/attestantio/go-eth2-client/api/v1"
eth2http "github.com/attestantio/go-eth2-client/http"
eth2mock "github.com/attestantio/go-eth2-client/mock"
Expand Down Expand Up @@ -389,6 +390,26 @@ func TestRouter(t *testing.T) {
testRouter(t, handler, callback)
})

t.Run("submit_randao_blinded_block", func(t *testing.T) {
handler := testHandler{
BlindedBeaconBlockProposalFunc: func(ctx context.Context, slot eth2p0.Slot, randaoReveal eth2p0.BLSSignature, graffiti []byte) (*eth2api.VersionedBlindedBeaconBlock, error) {
return nil, errors.New("not implemented")
},
}

callback := func(ctx context.Context, cl *eth2http.Service) {
slot := eth2p0.Slot(1)
randaoReveal := testutil.RandomEth2Signature()
graffiti := testutil.RandomBytes32()

res, err := cl.BlindedBeaconBlockProposal(ctx, slot, randaoReveal, graffiti)
require.Error(t, err)
require.Nil(t, res)
}

testRouter(t, handler, callback)
})

t.Run("submit_block_phase0", func(t *testing.T) {
block1 := &spec.VersionedSignedBeaconBlock{
Version: spec.DataVersionPhase0,
Expand Down Expand Up @@ -458,6 +479,29 @@ func TestRouter(t *testing.T) {
testRouter(t, handler, callback)
})

t.Run("submit_blinded_block_bellatrix", func(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to also add a testcase for router's proposeBlindedBlock 🙏

block1 := &eth2api.VersionedSignedBlindedBeaconBlock{
Version: spec.DataVersionBellatrix,
Bellatrix: &eth2v1.SignedBlindedBeaconBlock{
Message: testutil.RandomBellatrixBlindedBeaconBlock(t),
Signature: testutil.RandomEth2Signature(),
},
}
handler := testHandler{
SubmitBlindedBeaconBlockFunc: func(ctx context.Context, block *eth2api.VersionedSignedBlindedBeaconBlock) error {
require.Equal(t, block, block1)
return nil
},
}

callback := func(ctx context.Context, cl *eth2http.Service) {
err := cl.SubmitBlindedBeaconBlock(ctx, block1)
require.NoError(t, err)
}

testRouter(t, handler, callback)
})

t.Run("submit_voluntary_exit", func(t *testing.T) {
exit1 := testutil.RandomExit()

Expand Down Expand Up @@ -519,15 +563,17 @@ func testRawRouter(t *testing.T, handler testHandler, callback func(context.Cont
// mocked beacon-node endpoints required by the eth2http client during startup.
type testHandler struct {
Handler
ProxyHandler http.HandlerFunc
AttestationDataFunc func(ctx context.Context, slot eth2p0.Slot, commIdx eth2p0.CommitteeIndex) (*eth2p0.AttestationData, error)
AttesterDutiesFunc func(ctx context.Context, epoch eth2p0.Epoch, il []eth2p0.ValidatorIndex) ([]*eth2v1.AttesterDuty, error)
BeaconBlockProposalFunc func(ctx context.Context, slot eth2p0.Slot, randaoReveal eth2p0.BLSSignature, graffiti []byte) (*spec.VersionedBeaconBlock, error)
SubmitBeaconBlockFunc func(ctx context.Context, block *spec.VersionedSignedBeaconBlock) error
ProposerDutiesFunc func(ctx context.Context, epoch eth2p0.Epoch, il []eth2p0.ValidatorIndex) ([]*eth2v1.ProposerDuty, error)
ValidatorsFunc func(ctx context.Context, stateID string, indices []eth2p0.ValidatorIndex) (map[eth2p0.ValidatorIndex]*eth2v1.Validator, error)
ValidatorsByPubKeyFunc func(ctx context.Context, stateID string, pubkeys []eth2p0.BLSPubKey) (map[eth2p0.ValidatorIndex]*eth2v1.Validator, error)
SubmitVoluntaryExitFunc func(ctx context.Context, exit *eth2p0.SignedVoluntaryExit) error
ProxyHandler http.HandlerFunc
AttestationDataFunc func(ctx context.Context, slot eth2p0.Slot, commIdx eth2p0.CommitteeIndex) (*eth2p0.AttestationData, error)
AttesterDutiesFunc func(ctx context.Context, epoch eth2p0.Epoch, il []eth2p0.ValidatorIndex) ([]*eth2v1.AttesterDuty, error)
BeaconBlockProposalFunc func(ctx context.Context, slot eth2p0.Slot, randaoReveal eth2p0.BLSSignature, graffiti []byte) (*spec.VersionedBeaconBlock, error)
SubmitBeaconBlockFunc func(ctx context.Context, block *spec.VersionedSignedBeaconBlock) error
BlindedBeaconBlockProposalFunc func(ctx context.Context, slot eth2p0.Slot, randaoReveal eth2p0.BLSSignature, graffiti []byte) (*eth2api.VersionedBlindedBeaconBlock, error)
SubmitBlindedBeaconBlockFunc func(ctx context.Context, block *eth2api.VersionedSignedBlindedBeaconBlock) error
ProposerDutiesFunc func(ctx context.Context, epoch eth2p0.Epoch, il []eth2p0.ValidatorIndex) ([]*eth2v1.ProposerDuty, error)
ValidatorsFunc func(ctx context.Context, stateID string, indices []eth2p0.ValidatorIndex) (map[eth2p0.ValidatorIndex]*eth2v1.Validator, error)
ValidatorsByPubKeyFunc func(ctx context.Context, stateID string, pubkeys []eth2p0.BLSPubKey) (map[eth2p0.ValidatorIndex]*eth2v1.Validator, error)
SubmitVoluntaryExitFunc func(ctx context.Context, exit *eth2p0.SignedVoluntaryExit) error
}

func (h testHandler) AttestationData(ctx context.Context, slot eth2p0.Slot, commIdx eth2p0.CommitteeIndex) (*eth2p0.AttestationData, error) {
Expand All @@ -546,6 +592,14 @@ func (h testHandler) SubmitBeaconBlock(ctx context.Context, block *spec.Versione
return h.SubmitBeaconBlockFunc(ctx, block)
}

func (h testHandler) BlindedBeaconBlockProposal(ctx context.Context, slot eth2p0.Slot, randaoReveal eth2p0.BLSSignature, graffiti []byte) (*eth2api.VersionedBlindedBeaconBlock, error) {
return h.BlindedBeaconBlockProposalFunc(ctx, slot, randaoReveal, graffiti)
}

func (h testHandler) SubmitBlindedBeaconBlock(ctx context.Context, block *eth2api.VersionedSignedBlindedBeaconBlock) error {
return h.SubmitBlindedBeaconBlockFunc(ctx, block)
}

func (h testHandler) Validators(ctx context.Context, stateID string, indices []eth2p0.ValidatorIndex) (map[eth2p0.ValidatorIndex]*eth2v1.Validator, error) {
return h.ValidatorsFunc(ctx, stateID, indices)
}
Expand Down
1 change: 1 addition & 0 deletions core/validatorapi/validatorapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ type eth2Provider interface {
eth2client.BeaconBlockProposalProvider
eth2client.BeaconBlockSubmitter
eth2client.BlindedBeaconBlockSubmitter
eth2client.BlindedBeaconBlockProposalProvider
eth2client.DomainProvider
eth2client.ProposerDutiesProvider
eth2client.SlotsPerEpochProvider
Expand Down
9 changes: 4 additions & 5 deletions core/validatorapi/validatorapi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import (

eth2api "github.com/attestantio/go-eth2-client/api"
eth2v1 "github.com/attestantio/go-eth2-client/api/v1"
"github.com/attestantio/go-eth2-client/mock"
"github.com/attestantio/go-eth2-client/spec"
"github.com/attestantio/go-eth2-client/spec/altair"
"github.com/attestantio/go-eth2-client/spec/bellatrix"
Expand All @@ -45,7 +44,7 @@ import (

func TestComponent_ValidSubmitAttestations(t *testing.T) {
ctx := context.Background()
eth2Svc, err := mock.New(ctx)
eth2Svc, err := beaconmock.New()
require.NoError(t, err)

const (
Expand Down Expand Up @@ -123,7 +122,7 @@ func TestComponent_ValidSubmitAttestations(t *testing.T) {

func TestComponent_InvalidSubmitAttestations(t *testing.T) {
ctx := context.Background()
eth2Svc, err := mock.New(ctx)
eth2Svc, err := beaconmock.New()
require.NoError(t, err)

const (
Expand Down Expand Up @@ -323,7 +322,7 @@ func padTo(b []byte, size int) []byte {

func TestComponent_BeaconBlockProposal(t *testing.T) {
ctx := context.Background()
eth2Svc, err := mock.New(ctx)
eth2Svc, err := beaconmock.New()
require.NoError(t, err)

const (
Expand Down Expand Up @@ -618,7 +617,7 @@ func TestComponent_SubmitBeaconBlockInvalidBlock(t *testing.T) {

func TestComponent_BlindedBeaconBlockProposal(t *testing.T) {
ctx := context.Background()
eth2Svc, err := mock.New(ctx)
eth2Svc, err := beaconmock.New()
require.NoError(t, err)

const (
Expand Down
3 changes: 2 additions & 1 deletion testutil/validatormock/validatormock.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,10 @@ type Eth2Provider interface {
eth2client.AttestationDataProvider
eth2client.AttestationsSubmitter
eth2client.AttesterDutiesProvider
eth2client.BlindedBeaconBlockSubmitter
eth2client.BeaconBlockProposalProvider
eth2client.BeaconBlockSubmitter
eth2client.BlindedBeaconBlockProposalProvider
eth2client.BlindedBeaconBlockSubmitter
eth2client.DomainProvider
eth2client.ProposerDutiesProvider
eth2client.SlotsPerEpochProvider
Expand Down