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

/eth/v1/beacon/blinded_blocks/{block_id} API endpoint #11538

Merged
merged 15 commits into from
Oct 19, 2022
9 changes: 7 additions & 2 deletions beacon-chain/rpc/apimiddleware/custom_handlers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,19 @@ import (
)

type testSSZResponseJson struct {
Version string `json:"version"`
Data string `json:"data"`
Version string `json:"version"`
ExecutionOptimistic bool `json:"execution_optimistic"`
Data string `json:"data"`
}

func (t testSSZResponseJson) SSZVersion() string {
return t.Version
}

func (t testSSZResponseJson) SSZOptimistic() bool {
return t.ExecutionOptimistic
}

func (t testSSZResponseJson) SSZData() string {
return t.Data
}
Expand Down
52 changes: 52 additions & 0 deletions beacon-chain/rpc/apimiddleware/custom_hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,12 @@ type bellatrixBlockResponseJson struct {
ExecutionOptimistic bool `json:"execution_optimistic"`
}

type bellatrixBlindedBlockResponseJson struct {
Version string `json:"version"`
Data *SignedBlindedBeaconBlockBellatrixContainerJson `json:"data"`
ExecutionOptimistic bool `json:"execution_optimistic"`
}

func serializeV2Block(response interface{}) (apimiddleware.RunDefault, []byte, apimiddleware.ErrorJson) {
respContainer, ok := response.(*BlockV2ResponseJson)
if !ok {
Expand Down Expand Up @@ -485,6 +491,52 @@ func serializeV2Block(response interface{}) (apimiddleware.RunDefault, []byte, a
return false, j, nil
}

func serializeBlindedBlock(response interface{}) (apimiddleware.RunDefault, []byte, apimiddleware.ErrorJson) {
respContainer, ok := response.(*BlindedBlockResponseJson)
if !ok {
return false, nil, apimiddleware.InternalServerError(errors.New("container is not of the correct type"))
}

var actualRespContainer interface{}
switch {
case strings.EqualFold(respContainer.Version, strings.ToLower(ethpbv2.Version_PHASE0.String())):
actualRespContainer = &phase0BlockResponseJson{
Version: respContainer.Version,
Data: &SignedBeaconBlockContainerJson{
Message: respContainer.Data.Phase0Block,
Signature: respContainer.Data.Signature,
},
ExecutionOptimistic: respContainer.ExecutionOptimistic,
}
case strings.EqualFold(respContainer.Version, strings.ToLower(ethpbv2.Version_ALTAIR.String())):
actualRespContainer = &altairBlockResponseJson{
Version: respContainer.Version,
Data: &SignedBeaconBlockAltairContainerJson{
Message: respContainer.Data.AltairBlock,
Signature: respContainer.Data.Signature,
},
ExecutionOptimistic: respContainer.ExecutionOptimistic,
}
case strings.EqualFold(respContainer.Version, strings.ToLower(ethpbv2.Version_BELLATRIX.String())):
actualRespContainer = &bellatrixBlindedBlockResponseJson{
Version: respContainer.Version,
Data: &SignedBlindedBeaconBlockBellatrixContainerJson{
Message: respContainer.Data.BellatrixBlock,
Signature: respContainer.Data.Signature,
},
ExecutionOptimistic: respContainer.ExecutionOptimistic,
}
default:
return false, nil, apimiddleware.InternalServerError(fmt.Errorf("unsupported block version '%s'", respContainer.Version))
}

j, err := json.Marshal(actualRespContainer)
if err != nil {
return false, nil, apimiddleware.InternalServerErrorWithMessage(err, "could not marshal response")
}
return false, j, nil
}

type phase0StateResponseJson struct {
Version string `json:"version"`
Data *BeaconStateJson `json:"data"`
Expand Down
118 changes: 118 additions & 0 deletions beacon-chain/rpc/apimiddleware/custom_hooks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,124 @@ func TestSerializeV2Block(t *testing.T) {
})
}

func TestSerializeBlindedBlock(t *testing.T) {
t.Run("Phase 0", func(t *testing.T) {
response := &BlindedBlockResponseJson{
Version: ethpbv2.Version_PHASE0.String(),
Data: &SignedBlindedBeaconBlockContainerJson{
Phase0Block: &BeaconBlockJson{
Slot: "1",
ProposerIndex: "1",
ParentRoot: "root",
StateRoot: "root",
Body: &BeaconBlockBodyJson{},
},
Signature: "sig",
},
ExecutionOptimistic: true,
}
runDefault, j, errJson := serializeBlindedBlock(response)
require.Equal(t, nil, errJson)
require.Equal(t, apimiddleware.RunDefault(false), runDefault)
require.NotNil(t, j)
resp := &phase0BlockResponseJson{}
require.NoError(t, json.Unmarshal(j, resp))
require.NotNil(t, resp.Data)
require.NotNil(t, resp.Data.Message)
beaconBlock := resp.Data.Message
assert.Equal(t, "1", beaconBlock.Slot)
assert.Equal(t, "1", beaconBlock.ProposerIndex)
assert.Equal(t, "root", beaconBlock.ParentRoot)
assert.Equal(t, "root", beaconBlock.StateRoot)
assert.NotNil(t, beaconBlock.Body)
assert.Equal(t, true, resp.ExecutionOptimistic)
})

t.Run("Altair", func(t *testing.T) {
response := &BlindedBlockResponseJson{
Version: ethpbv2.Version_ALTAIR.String(),
Data: &SignedBlindedBeaconBlockContainerJson{
AltairBlock: &BeaconBlockAltairJson{
Slot: "1",
ProposerIndex: "1",
ParentRoot: "root",
StateRoot: "root",
Body: &BeaconBlockBodyAltairJson{},
},
Signature: "sig",
},
ExecutionOptimistic: true,
}
runDefault, j, errJson := serializeBlindedBlock(response)
require.Equal(t, nil, errJson)
require.Equal(t, apimiddleware.RunDefault(false), runDefault)
require.NotNil(t, j)
resp := &altairBlockResponseJson{}
require.NoError(t, json.Unmarshal(j, resp))
require.NotNil(t, resp.Data)
require.NotNil(t, resp.Data.Message)
beaconBlock := resp.Data.Message
assert.Equal(t, "1", beaconBlock.Slot)
assert.Equal(t, "1", beaconBlock.ProposerIndex)
assert.Equal(t, "root", beaconBlock.ParentRoot)
assert.Equal(t, "root", beaconBlock.StateRoot)
assert.NotNil(t, beaconBlock.Body)
assert.Equal(t, true, resp.ExecutionOptimistic)
})

t.Run("Bellatrix", func(t *testing.T) {
response := &BlindedBlockResponseJson{
Version: ethpbv2.Version_BELLATRIX.String(),
Data: &SignedBlindedBeaconBlockContainerJson{
BellatrixBlock: &BlindedBeaconBlockBellatrixJson{
Slot: "1",
ProposerIndex: "1",
ParentRoot: "root",
StateRoot: "root",
Body: &BlindedBeaconBlockBodyBellatrixJson{},
},
Signature: "sig",
},
ExecutionOptimistic: true,
}
runDefault, j, errJson := serializeBlindedBlock(response)
require.Equal(t, nil, errJson)
require.Equal(t, apimiddleware.RunDefault(false), runDefault)
require.NotNil(t, j)
resp := &bellatrixBlindedBlockResponseJson{}
require.NoError(t, json.Unmarshal(j, resp))
require.NotNil(t, resp.Data)
require.NotNil(t, resp.Data.Message)
beaconBlock := resp.Data.Message
assert.Equal(t, "1", beaconBlock.Slot)
assert.Equal(t, "1", beaconBlock.ProposerIndex)
assert.Equal(t, "root", beaconBlock.ParentRoot)
assert.Equal(t, "root", beaconBlock.StateRoot)
assert.NotNil(t, beaconBlock.Body)
assert.Equal(t, true, resp.ExecutionOptimistic)
})

t.Run("incorrect response type", func(t *testing.T) {
response := &types.Empty{}
runDefault, j, errJson := serializeBlindedBlock(response)
require.Equal(t, apimiddleware.RunDefault(false), runDefault)
require.Equal(t, 0, len(j))
require.NotNil(t, errJson)
assert.Equal(t, true, strings.Contains(errJson.Msg(), "container is not of the correct type"))
})

t.Run("unsupported block version", func(t *testing.T) {
response := &BlindedBlockResponseJson{
Version: "unsupported",
}
runDefault, j, errJson := serializeBlindedBlock(response)
require.Equal(t, apimiddleware.RunDefault(false), runDefault)
require.Equal(t, 0, len(j))
require.NotNil(t, errJson)
assert.Equal(t, true, strings.Contains(errJson.Msg(), "unsupported block version"))
})
}

func TestSerializeV2State(t *testing.T) {
t.Run("Phase 0", func(t *testing.T) {
response := &BeaconStateV2ResponseJson{
Expand Down
6 changes: 6 additions & 0 deletions beacon-chain/rpc/apimiddleware/endpoint_factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func (_ *BeaconEndpointFactory) Paths() []string {
"/eth/v2/beacon/blocks/{block_id}",
"/eth/v1/beacon/blocks/{block_id}/root",
"/eth/v1/beacon/blocks/{block_id}/attestations",
"/eth/v1/beacon/blinded_blocks/{block_id}",
"/eth/v1/beacon/pool/attestations",
"/eth/v1/beacon/pool/attester_slashings",
"/eth/v1/beacon/pool/proposer_slashings",
Expand Down Expand Up @@ -132,6 +133,11 @@ func (_ *BeaconEndpointFactory) Create(path string) (*apimiddleware.Endpoint, er
endpoint.GetResponse = &BlockRootResponseJson{}
case "/eth/v1/beacon/blocks/{block_id}/attestations":
endpoint.GetResponse = &BlockAttestationsResponseJson{}
case "/eth/v1/beacon/blinded_blocks/{block_id}":
endpoint.GetResponse = &BlindedBlockResponseJson{}
endpoint.Hooks = apimiddleware.HookCollection{
OnPreSerializeMiddlewareResponseIntoJson: serializeBlindedBlock,
}
case "/eth/v1/beacon/pool/attestations":
endpoint.RequestQueryParams = []apimiddleware.QueryParam{{Name: "slot"}, {Name: "committee_index"}}
endpoint.GetResponse = &AttestationsPoolResponseJson{}
Expand Down
27 changes: 25 additions & 2 deletions beacon-chain/rpc/apimiddleware/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@ type BlockV2ResponseJson struct {
ExecutionOptimistic bool `json:"execution_optimistic"`
}

type BlindedBlockResponseJson struct {
Version string `json:"version" enum:"true"`
Data *SignedBlindedBeaconBlockContainerJson `json:"data"`
ExecutionOptimistic bool `json:"execution_optimistic"`
}

type BlockRootResponseJson struct {
Data *BlockRootContainerJson `json:"data"`
ExecutionOptimistic bool `json:"execution_optimistic"`
Expand Down Expand Up @@ -333,6 +339,13 @@ type SignedBeaconBlockContainerV2Json struct {
Signature string `json:"signature" hex:"true"`
}

type SignedBlindedBeaconBlockContainerJson struct {
Phase0Block *BeaconBlockJson `json:"phase0_block"`
AltairBlock *BeaconBlockAltairJson `json:"altair_block"`
BellatrixBlock *BlindedBeaconBlockBellatrixJson `json:"bellatrix_block"`
Signature string `json:"signature" hex:"true"`
}

type BeaconBlockContainerV2Json struct {
Phase0Block *BeaconBlockJson `json:"phase0_block"`
AltairBlock *BeaconBlockAltairJson `json:"altair_block"`
Expand Down Expand Up @@ -827,6 +840,7 @@ type SszRequestJson struct {
// SszResponse is a common abstraction over all SSZ responses.
type SszResponse interface {
SSZVersion() string
SSZOptimistic() bool
SSZData() string
}

Expand All @@ -842,9 +856,14 @@ func (*SszResponseJson) SSZVersion() string {
return strings.ToLower(ethpbv2.Version_PHASE0.String())
}

func (*SszResponseJson) SSZOptimistic() bool {
return false
}

type VersionedSSZResponseJson struct {
Version string `json:"version"`
Data string `json:"data"`
Version string `json:"version"`
ExecutionOptimistic bool `json:"execution_optimistic"`
Data string `json:"data"`
}

func (ssz *VersionedSSZResponseJson) SSZData() string {
Expand All @@ -855,6 +874,10 @@ func (ssz *VersionedSSZResponseJson) SSZVersion() string {
return ssz.Version
}

func (ssz *VersionedSSZResponseJson) SSZOptimistic() bool {
return ssz.ExecutionOptimistic
}

// ---------------
// Events.
// ---------------
Expand Down
Loading