diff --git a/beaconclient/mock_beacon_instance.go b/beaconclient/mock_beacon_instance.go index a09127e9..01ba298c 100644 --- a/beaconclient/mock_beacon_instance.go +++ b/beaconclient/mock_beacon_instance.go @@ -4,7 +4,6 @@ import ( "sync" "time" - "github.com/attestantio/go-eth2-client/spec" "github.com/flashbots/mev-boost-relay/common" ) @@ -107,7 +106,7 @@ func (c *MockBeaconInstance) addDelay() { } } -func (c *MockBeaconInstance) PublishBlock(block *spec.VersionedSignedBeaconBlock, broadcaseMode BroadcastMode) (code int, err error) { +func (c *MockBeaconInstance) PublishBlock(block *common.VersionedSignedBlockRequest, broadcaseMode BroadcastMode) (code int, err error) { return 0, nil } diff --git a/beaconclient/mock_multi_beacon_client.go b/beaconclient/mock_multi_beacon_client.go index e5935b5e..da3bed4f 100644 --- a/beaconclient/mock_multi_beacon_client.go +++ b/beaconclient/mock_multi_beacon_client.go @@ -1,8 +1,8 @@ package beaconclient import ( - "github.com/attestantio/go-eth2-client/spec" "github.com/attestantio/go-eth2-client/spec/capella" + "github.com/flashbots/mev-boost-relay/common" ) type MockMultiBeaconClient struct{} @@ -28,7 +28,7 @@ func (*MockMultiBeaconClient) GetProposerDuties(epoch uint64) (*ProposerDutiesRe return nil, nil } -func (*MockMultiBeaconClient) PublishBlock(block *spec.VersionedSignedBeaconBlock) (code int, err error) { +func (*MockMultiBeaconClient) PublishBlock(block *common.VersionedSignedBlockRequest) (code int, err error) { return 0, nil } diff --git a/beaconclient/multi_beacon_client.go b/beaconclient/multi_beacon_client.go index 466092f5..33f6056f 100644 --- a/beaconclient/multi_beacon_client.go +++ b/beaconclient/multi_beacon_client.go @@ -8,7 +8,7 @@ import ( "strings" "sync" - "github.com/attestantio/go-eth2-client/spec" + "github.com/flashbots/mev-boost-relay/common" "github.com/sirupsen/logrus" uberatomic "go.uber.org/atomic" ) @@ -29,7 +29,11 @@ const ( ) func (b BroadcastMode) String() string { - return [...]string{"gossip", "consensus", "consensus_and_equivocation"}[b] + broadcastModeStrings := [...]string{"gossip", "consensus", "consensus_and_equivocation"} + if int(b) >= len(broadcastModeStrings) { + return "invalid broadcast mode value" + } + return broadcastModeStrings[b] } // IMultiBeaconClient is the interface for the MultiBeaconClient, which can manage several beacon client instances under the hood @@ -42,7 +46,7 @@ type IMultiBeaconClient interface { // GetStateValidators returns all active and pending validators from the beacon node GetStateValidators(stateID string) (*GetStateValidatorsResponse, error) GetProposerDuties(epoch uint64) (*ProposerDutiesResponse, error) - PublishBlock(block *spec.VersionedSignedBeaconBlock) (code int, err error) + PublishBlock(block *common.VersionedSignedBlockRequest) (code int, err error) GetGenesis() (*GetGenesisResponse, error) GetSpec() (spec *GetSpecResponse, err error) GetForkSchedule() (spec *GetForkScheduleResponse, err error) @@ -60,7 +64,7 @@ type IBeaconInstance interface { GetStateValidators(stateID string) (*GetStateValidatorsResponse, error) GetProposerDuties(epoch uint64) (*ProposerDutiesResponse, error) GetURI() string - PublishBlock(block *spec.VersionedSignedBeaconBlock, broadcastMode BroadcastMode) (code int, err error) + PublishBlock(block *common.VersionedSignedBlockRequest, broadcastMode BroadcastMode) (code int, err error) GetGenesis() (*GetGenesisResponse, error) GetSpec() (spec *GetSpecResponse, err error) GetForkSchedule() (spec *GetForkScheduleResponse, err error) @@ -255,7 +259,7 @@ type publishResp struct { } // PublishBlock publishes the signed beacon block via https://ethereum.github.io/beacon-APIs/#/ValidatorRequiredApi/publishBlock -func (c *MultiBeaconClient) PublishBlock(block *spec.VersionedSignedBeaconBlock) (code int, err error) { +func (c *MultiBeaconClient) PublishBlock(block *common.VersionedSignedBlockRequest) (code int, err error) { slot, err := block.Slot() if err != nil { c.log.WithError(err).Warn("failed to publish block as block slot is missing") diff --git a/beaconclient/prod_beacon_instance.go b/beaconclient/prod_beacon_instance.go index 0ed63126..3b669817 100644 --- a/beaconclient/prod_beacon_instance.go +++ b/beaconclient/prod_beacon_instance.go @@ -7,7 +7,6 @@ import ( "os" "time" - "github.com/attestantio/go-eth2-client/spec" "github.com/attestantio/go-eth2-client/spec/capella" "github.com/flashbots/mev-boost-relay/common" "github.com/r3labs/sse/v2" @@ -269,7 +268,7 @@ func (c *ProdBeaconInstance) GetURI() string { return c.beaconURI } -func (c *ProdBeaconInstance) PublishBlock(block *common.SignedBeaconBlock, broadcastMode BroadcastMode) (code int, err error) { +func (c *ProdBeaconInstance) PublishBlock(block *common.VersionedSignedBlockRequest, broadcastMode BroadcastMode) (code int, err error) { var uri string if c.ffUseV2PublishBlockEndpoint { uri = fmt.Sprintf("%s/eth/v2/beacon/blocks?broadcast_validation=%s", c.beaconURI, broadcastMode.String()) @@ -277,8 +276,8 @@ func (c *ProdBeaconInstance) PublishBlock(block *common.SignedBeaconBlock, broad uri = fmt.Sprintf("%s/eth/v1/beacon/blocks", c.beaconURI) } headers := http.Header{} - headers.Add("Eth-Consensus-Version", common.ForkVersionStringCapella) // optional in v1, required in v2 - return fetchBeacon(http.MethodPost, uri, block.Capella, nil, nil, headers) + headers.Add("Eth-Consensus-Version", block.Version.String()) // optional in v1, required in v2 + return fetchBeacon(http.MethodPost, uri, block, nil, nil, headers) } type GetGenesisResponse struct { diff --git a/common/ssz_test.go b/common/ssz_test.go index 790b57e6..3726e763 100644 --- a/common/ssz_test.go +++ b/common/ssz_test.go @@ -1,6 +1,7 @@ package common import ( + "bytes" "encoding/json" "os" "testing" @@ -12,21 +13,35 @@ import ( ) func TestSSZBuilderSubmission(t *testing.T) { - byteValue := LoadGzippedBytes(t, "../testdata/submitBlockPayloadCapella_Goerli.json.gz") + // json matches marshalled SSZ + jsonBytes := LoadGzippedBytes(t, "../testdata/submitBlockPayloadCapella_Goerli.json.gz") - depositData := new(capella.SubmitBlockRequest) - err := json.Unmarshal(byteValue, &depositData) + submitBlockData := new(VersionedSubmitBlockRequest) + err := json.Unmarshal(jsonBytes, &submitBlockData) require.NoError(t, err) - ssz, err := depositData.MarshalSSZ() + require.NotNil(t, submitBlockData.Capella) + marshalledSszBytes, err := submitBlockData.Capella.MarshalSSZ() require.NoError(t, err) - sszExpectedBytes := LoadGzippedBytes(t, "../testdata/submitBlockPayloadCapella_Goerli.ssz.gz") - require.Equal(t, sszExpectedBytes, ssz) + sszBytes := LoadGzippedBytes(t, "../testdata/submitBlockPayloadCapella_Goerli.ssz.gz") + require.Equal(t, sszBytes, marshalledSszBytes) - htr, err := depositData.HashTreeRoot() + htr, err := submitBlockData.Capella.HashTreeRoot() require.NoError(t, err) require.Equal(t, "0x014c218ba41c2ed5388e7f0ed055e109b83692c772de5c2800140a95a4b66d13", hexutil.Encode(htr[:])) + + // marshalled json matches ssz + submitBlockSSZ := new(VersionedSubmitBlockRequest) + err = submitBlockSSZ.UnmarshalSSZ(sszBytes) + require.NoError(t, err) + marshalledJSONBytes, err := json.Marshal(submitBlockSSZ) + require.NoError(t, err) + // trim white space from expected json + buffer := new(bytes.Buffer) + err = json.Compact(buffer, jsonBytes) + require.NoError(t, err) + require.Equal(t, buffer.Bytes(), bytes.ToLower(marshalledJSONBytes)) } func TestSSZGetHeaderResponse(t *testing.T) { diff --git a/common/test_utils.go b/common/test_utils.go index eabbd7d8..4d55463e 100644 --- a/common/test_utils.go +++ b/common/test_utils.go @@ -74,19 +74,21 @@ var ValidPayloadRegisterValidator = apiv1.SignedValidatorRegistration{ "0xaf12df007a0c78abb5575067e5f8b089cfcc6227e4a91db7dd8cf517fe86fb944ead859f0781277d9b78c672e4a18c5d06368b603374673cf2007966cece9540f3a1b3f6f9e1bf421d779c4e8010368e6aac134649c7a009210780d401a778a5"), } -func TestBuilderSubmitBlockRequest(sk *bls.SecretKey, bid *BidTraceV2) spec.VersionedSubmitBlockRequest { +func TestBuilderSubmitBlockRequest(sk *bls.SecretKey, bid *BidTraceV2) VersionedSubmitBlockRequest { signature, err := ssz.SignMessage(bid, ssz.DomainBuilder, sk) check(err, " SignMessage: ", bid, sk) - return spec.VersionedSubmitBlockRequest{ //nolint:exhaustruct - Version: consensusspec.DataVersionCapella, - Capella: &capella.SubmitBlockRequest{ - Message: &bid.BidTrace, - Signature: [96]byte(signature), - ExecutionPayload: &consensuscapella.ExecutionPayload{ //nolint:exhaustruct - Transactions: []bellatrix.Transaction{[]byte{0x03}}, - Timestamp: bid.Slot * 12, // 12 seconds per slot. - PrevRandao: _HexToHash("0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), - Withdrawals: []*consensuscapella.Withdrawal{}, + return VersionedSubmitBlockRequest{ + VersionedSubmitBlockRequest: spec.VersionedSubmitBlockRequest{ //nolint:exhaustruct + Version: consensusspec.DataVersionCapella, + Capella: &capella.SubmitBlockRequest{ + Message: &bid.BidTrace, + Signature: [96]byte(signature), + ExecutionPayload: &consensuscapella.ExecutionPayload{ //nolint:exhaustruct + Transactions: []bellatrix.Transaction{[]byte{0x03}}, + Timestamp: bid.Slot * 12, // 12 seconds per slot. + PrevRandao: _HexToHash("0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), + Withdrawals: []*consensuscapella.Withdrawal{}, + }, }, }, } diff --git a/common/types_spec.go b/common/types_spec.go index 5fb2685c..bff5a524 100644 --- a/common/types_spec.go +++ b/common/types_spec.go @@ -6,8 +6,11 @@ import ( "github.com/attestantio/go-builder-client/api" "github.com/attestantio/go-builder-client/api/capella" + "github.com/attestantio/go-builder-client/api/deneb" "github.com/attestantio/go-builder-client/spec" consensusapi "github.com/attestantio/go-eth2-client/api" + apiv1capella "github.com/attestantio/go-eth2-client/api/v1/capella" + apiv1deneb "github.com/attestantio/go-eth2-client/api/v1/deneb" consensusspec "github.com/attestantio/go-eth2-client/spec" consensuscapella "github.com/attestantio/go-eth2-client/spec/capella" "github.com/attestantio/go-eth2-client/spec/phase0" @@ -36,7 +39,7 @@ var NilResponse = struct{}{} var ZeroU256 = boostTypes.IntToU256(0) -func BuildGetHeaderResponse(payload *spec.VersionedSubmitBlockRequest, sk *bls.SecretKey, pubkey *phase0.BLSPubKey, domain phase0.Domain) (*spec.VersionedSignedBuilderBid, error) { +func BuildGetHeaderResponse(payload *VersionedSubmitBlockRequest, sk *bls.SecretKey, pubkey *phase0.BLSPubKey, domain phase0.Domain) (*spec.VersionedSignedBuilderBid, error) { if payload == nil { return nil, ErrMissingRequest } @@ -59,7 +62,7 @@ func BuildGetHeaderResponse(payload *spec.VersionedSubmitBlockRequest, sk *bls.S return nil, ErrEmptyPayload } -func BuildGetPayloadResponse(payload *spec.VersionedSubmitBlockRequest) (*api.VersionedExecutionPayload, error) { +func BuildGetPayloadResponse(payload *VersionedSubmitBlockRequest) (*api.VersionedExecutionPayload, error) { if payload.Capella != nil { return &api.VersionedExecutionPayload{ Version: consensusspec.DataVersionCapella, @@ -70,7 +73,7 @@ func BuildGetPayloadResponse(payload *spec.VersionedSubmitBlockRequest) (*api.Ve return nil, ErrEmptyPayload } -func BuilderSubmitBlockRequestToSignedBuilderBid(req *spec.VersionedSubmitBlockRequest, sk *bls.SecretKey, pubkey *phase0.BLSPubKey, domain phase0.Domain) (*spec.VersionedSignedBuilderBid, error) { +func BuilderSubmitBlockRequestToSignedBuilderBid(req *VersionedSubmitBlockRequest, sk *bls.SecretKey, pubkey *phase0.BLSPubKey, domain phase0.Domain) (*spec.VersionedSignedBuilderBid, error) { value, err := req.Value() if err != nil { return nil, err @@ -167,8 +170,8 @@ func CapellaPayloadToPayloadHeader(p *consensuscapella.ExecutionPayload) (*conse }, nil } -func SignedBlindedBeaconBlockToBeaconBlock(signedBlindedBeaconBlock *consensusapi.VersionedSignedBlindedBeaconBlock, executionPayload *api.VersionedExecutionPayload) *consensusspec.VersionedSignedBeaconBlock { - var signedBeaconBlock consensusspec.VersionedSignedBeaconBlock +func SignedBlindedBeaconBlockToBeaconBlock(signedBlindedBeaconBlock *VersionedSignedBlindedBlockRequest, executionPayload *api.VersionedExecutionPayload) *VersionedSignedBlockRequest { + var signedBeaconBlock VersionedSignedBlockRequest capellaBlindedBlock := signedBlindedBeaconBlock.Capella if capellaBlindedBlock != nil { signedBeaconBlock.Capella = &consensuscapella.SignedBeaconBlock{ @@ -198,20 +201,12 @@ func SignedBlindedBeaconBlockToBeaconBlock(signedBlindedBeaconBlock *consensusap } type BuilderBlockValidationRequest struct { - spec.VersionedSubmitBlockRequest + VersionedSubmitBlockRequest RegisteredGasLimit uint64 `json:"registered_gas_limit,string"` } func (r *BuilderBlockValidationRequest) MarshalJSON() ([]byte, error) { - var blockRequest []byte - var err error - - switch r.VersionedSubmitBlockRequest.Version { //nolint:exhaustive - case consensusspec.DataVersionCapella: - blockRequest, err = r.VersionedSubmitBlockRequest.Capella.MarshalJSON() - default: - return nil, errors.Wrap(ErrInvalidVersion, fmt.Sprintf("%d is not supported", r.VersionedSubmitBlockRequest.Version)) - } + blockRequest, err := json.Marshal(r.VersionedSubmitBlockRequest) if err != nil { return nil, err } @@ -226,3 +221,129 @@ func (r *BuilderBlockValidationRequest) MarshalJSON() ([]byte, error) { gasLimit[0] = ',' return append(blockRequest[:len(blockRequest)-1], gasLimit...), nil } + +type VersionedSubmitBlockRequest struct { + spec.VersionedSubmitBlockRequest +} + +func (r *VersionedSubmitBlockRequest) UnmarshalSSZ(input []byte) error { + var err error + + deneb := new(deneb.SubmitBlockRequest) + if err = deneb.UnmarshalSSZ(input); err == nil { + r.Version = consensusspec.DataVersionDeneb + r.Deneb = deneb + return nil + } + + capella := new(capella.SubmitBlockRequest) + if err = capella.UnmarshalSSZ(input); err == nil { + r.Version = consensusspec.DataVersionCapella + r.Capella = capella + return nil + } + return errors.Wrap(err, "failed to unmarshal SubmitBlockRequest SSZ") +} + +func (r *VersionedSubmitBlockRequest) MarshalJSON() ([]byte, error) { + switch r.Version { + case consensusspec.DataVersionCapella: + return json.Marshal(r.Capella) + case consensusspec.DataVersionDeneb: + return json.Marshal(r.Deneb) + case consensusspec.DataVersionUnknown, consensusspec.DataVersionPhase0, consensusspec.DataVersionAltair, consensusspec.DataVersionBellatrix: + fallthrough + default: + return nil, errors.Wrap(ErrInvalidVersion, fmt.Sprintf("%d is not supported", r.Version)) + } +} + +func (r *VersionedSubmitBlockRequest) UnmarshalJSON(input []byte) error { + var err error + + deneb := new(deneb.SubmitBlockRequest) + if err = json.Unmarshal(input, deneb); err == nil { + r.Version = consensusspec.DataVersionDeneb + r.Deneb = deneb + return nil + } + capella := new(capella.SubmitBlockRequest) + if err = json.Unmarshal(input, capella); err == nil { + r.Version = consensusspec.DataVersionCapella + r.Capella = capella + return nil + } + return errors.Wrap(err, "failed to unmarshal SubmitBlockRequest") +} + +type VersionedSignedBlockRequest struct { + consensusapi.VersionedBlockRequest +} + +func (r *VersionedSignedBlockRequest) MarshalJSON() ([]byte, error) { + switch r.Version { + case consensusspec.DataVersionCapella: + return json.Marshal(r.Capella) + case consensusspec.DataVersionDeneb: + return json.Marshal(r.Deneb) + case consensusspec.DataVersionUnknown, consensusspec.DataVersionPhase0, consensusspec.DataVersionAltair, consensusspec.DataVersionBellatrix: + fallthrough + default: + return nil, errors.Wrap(ErrInvalidVersion, fmt.Sprintf("%d is not supported", r.Version)) + } +} + +func (r *VersionedSignedBlockRequest) UnmarshalJSON(input []byte) error { + var err error + + deneb := new(apiv1deneb.SignedBlockContents) + if err = json.Unmarshal(input, deneb); err == nil { + r.Version = consensusspec.DataVersionDeneb + r.Deneb = deneb + return nil + } + + capella := new(consensuscapella.SignedBeaconBlock) + if err = json.Unmarshal(input, capella); err == nil { + r.Version = consensusspec.DataVersionCapella + r.Capella = capella + return nil + } + return errors.Wrap(err, "failed to unmarshal SignedBeaconBlockRequest") +} + +type VersionedSignedBlindedBlockRequest struct { + consensusapi.VersionedBlindedBlockRequest +} + +func (r *VersionedSignedBlindedBlockRequest) MarshalJSON() ([]byte, error) { + switch r.Version { + case consensusspec.DataVersionCapella: + return json.Marshal(r.Capella) + case consensusspec.DataVersionDeneb: + return json.Marshal(r.Deneb) + case consensusspec.DataVersionUnknown, consensusspec.DataVersionPhase0, consensusspec.DataVersionAltair, consensusspec.DataVersionBellatrix: + fallthrough + default: + return nil, errors.Wrap(ErrInvalidVersion, fmt.Sprintf("%d is not supported", r.Version)) + } +} + +func (r *VersionedSignedBlindedBlockRequest) UnmarshalJSON(input []byte) error { + var err error + + deneb := new(apiv1deneb.SignedBlindedBlockContents) + if err = json.Unmarshal(input, deneb); err == nil { + r.Version = consensusspec.DataVersionDeneb + r.Deneb = deneb + return nil + } + + capella := new(apiv1capella.SignedBlindedBeaconBlock) + if err = json.Unmarshal(input, capella); err == nil { + r.Version = consensusspec.DataVersionCapella + r.Capella = capella + return nil + } + return errors.Wrap(err, "failed to unmarshal SignedBlindedBeaconBlock") +} diff --git a/common/types_spec_test.go b/common/types_spec_test.go new file mode 100644 index 00000000..a8774f36 --- /dev/null +++ b/common/types_spec_test.go @@ -0,0 +1,60 @@ +package common + +import ( + "bytes" + "encoding/json" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestSubmitBuilderBlockJSON(t *testing.T) { + jsonBytes := LoadGzippedBytes(t, "../testdata/submitBlockPayloadCapella_Goerli.json.gz") + + submitBlockData := new(VersionedSubmitBlockRequest) + err := json.Unmarshal(jsonBytes, &submitBlockData) + require.NoError(t, err) + + marshalledJSONBytes, err := json.Marshal(submitBlockData) + require.NoError(t, err) + buffer := new(bytes.Buffer) + err = json.Compact(buffer, jsonBytes) + require.NoError(t, err) + expectedJSONBytes := buffer.Bytes() + + require.Equal(t, expectedJSONBytes, bytes.ToLower(marshalledJSONBytes)) +} + +func TestSignedBeaconBlockJSON(t *testing.T) { + jsonBytes := LoadGzippedBytes(t, "../testdata/signedBeaconBlock_Goerli.json.gz") + buffer := new(bytes.Buffer) + err := json.Compact(buffer, jsonBytes) + require.NoError(t, err) + expectedJSONBytes := buffer.Bytes() + + blockRequest := new(VersionedSignedBlockRequest) + err = json.Unmarshal(jsonBytes, blockRequest) + require.NoError(t, err) + + marshalledJSONBytes, err := json.Marshal(blockRequest) + require.NoError(t, err) + + require.Equal(t, expectedJSONBytes, bytes.ToLower(marshalledJSONBytes)) +} + +func TestSignedBlindedBlockJSON(t *testing.T) { + jsonBytes := LoadGzippedBytes(t, "../testdata/signedBlindedBeaconBlock_Goerli.json.gz") + buffer := new(bytes.Buffer) + err := json.Compact(buffer, jsonBytes) + require.NoError(t, err) + expectedJSONBytes := buffer.Bytes() + + blockRequest := new(VersionedSignedBlindedBlockRequest) + err = json.Unmarshal(jsonBytes, blockRequest) + require.NoError(t, err) + + marshalledJSONBytes, err := json.Marshal(blockRequest) + require.NoError(t, err) + + require.Equal(t, expectedJSONBytes, bytes.ToLower(marshalledJSONBytes)) +} diff --git a/common/utils.go b/common/utils.go index 33b33468..11a946c3 100644 --- a/common/utils.go +++ b/common/utils.go @@ -185,7 +185,7 @@ type CreateTestBlockSubmissionOpts struct { ProposerPubkey string } -func CreateTestBlockSubmission(t *testing.T, builderPubkey string, value *uint256.Int, opts *CreateTestBlockSubmissionOpts) (payload *spec.VersionedSubmitBlockRequest, getPayloadResponse *api.VersionedExecutionPayload, getHeaderResponse *spec.VersionedSignedBuilderBid) { +func CreateTestBlockSubmission(t *testing.T, builderPubkey string, value *uint256.Int, opts *CreateTestBlockSubmissionOpts) (payload *VersionedSubmitBlockRequest, getPayloadResponse *api.VersionedExecutionPayload, getHeaderResponse *spec.VersionedSignedBuilderBid) { t.Helper() var err error @@ -216,18 +216,20 @@ func CreateTestBlockSubmission(t *testing.T, builderPubkey string, value *uint25 builderPk, err := StrToPhase0Pubkey(builderPubkey) require.NoError(t, err) - payload = &spec.VersionedSubmitBlockRequest{ //nolint:exhaustruct - Version: consensusspec.DataVersionCapella, - Capella: &capella.SubmitBlockRequest{ - Message: &apiv1.BidTrace{ //nolint:exhaustruct - BuilderPubkey: builderPk, - Value: value, - Slot: slot, - ParentHash: parentHash, - ProposerPubkey: proposerPk, + payload = &VersionedSubmitBlockRequest{ + VersionedSubmitBlockRequest: spec.VersionedSubmitBlockRequest{ //nolint:exhaustruct + Version: consensusspec.DataVersionCapella, + Capella: &capella.SubmitBlockRequest{ + Message: &apiv1.BidTrace{ //nolint:exhaustruct + BuilderPubkey: builderPk, + Value: value, + Slot: slot, + ParentHash: parentHash, + ProposerPubkey: proposerPk, + }, + ExecutionPayload: &capellaspec.ExecutionPayload{}, //nolint:exhaustruct + Signature: phase0.BLSSignature{}, }, - ExecutionPayload: &capellaspec.ExecutionPayload{}, //nolint:exhaustruct - Signature: phase0.BLSSignature{}, }, } @@ -252,7 +254,7 @@ func GetEnvDurationSec(key string, defaultValueSec int) time.Duration { return time.Duration(defaultValueSec) * time.Second } -func GetBlockSubmissionInfo(submission *spec.VersionedSubmitBlockRequest) (*BlockSubmissionInfo, error) { +func GetBlockSubmissionInfo(submission *VersionedSubmitBlockRequest) (*BlockSubmissionInfo, error) { bidTrace, err := submission.BidTrace() if err != nil { return nil, err @@ -347,7 +349,7 @@ func GetBlockSubmissionInfo(submission *spec.VersionedSubmitBlockRequest) (*Bloc }, nil } -func GetBlockSubmissionExecutionPayload(submission *spec.VersionedSubmitBlockRequest) (*api.VersionedExecutionPayload, error) { +func GetBlockSubmissionExecutionPayload(submission *VersionedSubmitBlockRequest) (*api.VersionedExecutionPayload, error) { if submission.Capella != nil { return &api.VersionedExecutionPayload{ Version: consensusspec.DataVersionCapella, diff --git a/common/utils_test.go b/common/utils_test.go index 70ed2056..80f88504 100644 --- a/common/utils_test.go +++ b/common/utils_test.go @@ -7,13 +7,6 @@ import ( "os" "testing" - "github.com/attestantio/go-builder-client/api/bellatrix" - "github.com/attestantio/go-builder-client/api/capella" - apiv1 "github.com/attestantio/go-builder-client/api/v1" - "github.com/attestantio/go-builder-client/spec" - consensusspec "github.com/attestantio/go-eth2-client/spec" - consensusbellatrix "github.com/attestantio/go-eth2-client/spec/bellatrix" - consensuscapella "github.com/attestantio/go-eth2-client/spec/capella" "github.com/ethereum/go-ethereum/common" boostTypes "github.com/flashbots/go-boost-utils/types" "github.com/stretchr/testify/require" @@ -105,80 +98,3 @@ func TestGetEnvStrSlice(t *testing.T) { require.Equal(t, "str2", r[1]) os.Unsetenv(testEnvVar) } - -func TestGetBlockSubmissionInfo(t *testing.T) { - cases := []struct { - name string - payload *spec.VersionedSubmitBlockRequest - expected *BlockSubmissionInfo - err string - }{ - { - name: "valid capella", - payload: &spec.VersionedSubmitBlockRequest{ - Version: consensusspec.DataVersionCapella, - Capella: &capella.SubmitBlockRequest{ - Message: &apiv1.BidTrace{}, - ExecutionPayload: &consensuscapella.ExecutionPayload{}, - }, - }, - expected: &BlockSubmissionInfo{ - BidTrace: &apiv1.BidTrace{}, - }, - }, - { - name: "unsupported version", - payload: &spec.VersionedSubmitBlockRequest{ - Version: consensusspec.DataVersionBellatrix, - Bellatrix: &bellatrix.SubmitBlockRequest{ - Message: &apiv1.BidTrace{}, - ExecutionPayload: &consensusbellatrix.ExecutionPayload{}, - }, - }, - expected: nil, - err: "unsupported version", - }, - { - name: "missing data", - payload: &spec.VersionedSubmitBlockRequest{ - Version: consensusspec.DataVersionCapella, - }, - expected: nil, - err: "no data", - }, - { - name: "missing message", - payload: &spec.VersionedSubmitBlockRequest{ - Version: consensusspec.DataVersionCapella, - Capella: &capella.SubmitBlockRequest{ - ExecutionPayload: &consensuscapella.ExecutionPayload{}, - }, - }, - expected: nil, - err: "no data message", - }, - { - name: "missing execution payload", - payload: &spec.VersionedSubmitBlockRequest{ - Version: consensusspec.DataVersionCapella, - Capella: &capella.SubmitBlockRequest{ - Message: &apiv1.BidTrace{}, - }, - }, - expected: nil, - err: "no data execution payload", - }, - } - - for _, tc := range cases { - t.Run(tc.name, func(t *testing.T) { - submission, err := GetBlockSubmissionInfo(tc.payload) - require.Equal(t, tc.expected, submission) - if tc.err == "" { - require.Nil(t, err) - } else { - require.Equal(t, tc.err, err.Error()) - } - }) - } -} diff --git a/database/database.go b/database/database.go index 578ca62a..2998325c 100644 --- a/database/database.go +++ b/database/database.go @@ -10,9 +10,6 @@ import ( "time" apiv1 "github.com/attestantio/go-builder-client/api/v1" - "github.com/attestantio/go-builder-client/spec" - consensusapi "github.com/attestantio/go-eth2-client/api" - consensusspec "github.com/attestantio/go-eth2-client/spec" "github.com/flashbots/mev-boost-relay/common" "github.com/flashbots/mev-boost-relay/database/migrations" "github.com/flashbots/mev-boost-relay/database/vars" @@ -28,7 +25,7 @@ type IDatabaseService interface { GetValidatorRegistration(pubkey string) (*ValidatorRegistrationEntry, error) GetValidatorRegistrationsForPubkeys(pubkeys []string) ([]*ValidatorRegistrationEntry, error) - SaveBuilderBlockSubmission(payload *spec.VersionedSubmitBlockRequest, requestError, validationError error, receivedAt, eligibleAt time.Time, wasSimulated, saveExecPayload bool, profile common.Profile, optimisticSubmission bool) (entry *BuilderBlockSubmissionEntry, err error) + SaveBuilderBlockSubmission(payload *common.VersionedSubmitBlockRequest, requestError, validationError error, receivedAt, eligibleAt time.Time, wasSimulated, saveExecPayload bool, profile common.Profile, optimisticSubmission bool) (entry *BuilderBlockSubmissionEntry, err error) GetBlockSubmissionEntry(slot uint64, proposerPubkey, blockHash string) (entry *BuilderBlockSubmissionEntry, err error) GetBuilderSubmissions(filters GetBuilderSubmissionsFilters) ([]*BuilderBlockSubmissionEntry, error) GetBuilderSubmissionsBySlots(slotFrom, slotTo uint64) (entries []*BuilderBlockSubmissionEntry, err error) @@ -37,7 +34,7 @@ type IDatabaseService interface { GetExecutionPayloads(idFirst, idLast uint64) (entries []*ExecutionPayloadEntry, err error) DeleteExecutionPayloads(idFirst, idLast uint64) error - SaveDeliveredPayload(bidTrace *common.BidTraceV2, signedBlindedBeaconBlock *consensusapi.VersionedSignedBlindedBeaconBlock, signedAt time.Time, publishMs uint64) error + SaveDeliveredPayload(bidTrace *common.BidTraceV2, signedBlindedBeaconBlock *common.VersionedSignedBlindedBlockRequest, signedAt time.Time, publishMs uint64) error GetNumDeliveredPayloads() (uint64, error) GetRecentDeliveredPayloads(filters GetPayloadsFilters) ([]*DeliveredPayloadEntry, error) GetDeliveredPayloads(idFirst, idLast uint64) (entries []*DeliveredPayloadEntry, err error) @@ -50,8 +47,8 @@ type IDatabaseService interface { UpsertBlockBuilderEntryAfterSubmission(lastSubmission *BuilderBlockSubmissionEntry, isError bool) error IncBlockBuilderStatsAfterGetPayload(builderPubkey string) error - InsertBuilderDemotion(submitBlockRequest *spec.VersionedSubmitBlockRequest, simError error) error - UpdateBuilderDemotion(trace *common.BidTraceV2, signedBlock *consensusspec.VersionedSignedBeaconBlock, signedRegistration *apiv1.SignedValidatorRegistration) error + InsertBuilderDemotion(submitBlockRequest *common.VersionedSubmitBlockRequest, simError error) error + UpdateBuilderDemotion(trace *common.BidTraceV2, signedBlock *common.VersionedSignedBlockRequest, signedRegistration *apiv1.SignedValidatorRegistration) error GetBuilderDemotion(trace *common.BidTraceV2) (*BuilderDemotionEntry, error) GetTooLateGetPayload(slot uint64) (entries []*TooLateGetPayloadEntry, err error) @@ -178,7 +175,7 @@ func (s *DatabaseService) GetLatestValidatorRegistrations(timestampOnly bool) ([ return registrations, err } -func (s *DatabaseService) SaveBuilderBlockSubmission(payload *spec.VersionedSubmitBlockRequest, requestError, validationError error, receivedAt, eligibleAt time.Time, wasSimulated, saveExecPayload bool, profile common.Profile, optimisticSubmission bool) (entry *BuilderBlockSubmissionEntry, err error) { +func (s *DatabaseService) SaveBuilderBlockSubmission(payload *common.VersionedSubmitBlockRequest, requestError, validationError error, receivedAt, eligibleAt time.Time, wasSimulated, saveExecPayload bool, profile common.Profile, optimisticSubmission bool) (entry *BuilderBlockSubmissionEntry, err error) { // Save execution_payload: insert, or if already exists update to be able to return the id ('on conflict do nothing' doesn't return an id) execPayloadEntry, err := PayloadToExecPayloadEntry(payload) if err != nil { @@ -275,7 +272,7 @@ func (s *DatabaseService) GetExecutionPayloadEntryBySlotPkHash(slot uint64, prop return entry, err } -func (s *DatabaseService) SaveDeliveredPayload(bidTrace *common.BidTraceV2, signedBlindedBeaconBlock *consensusapi.VersionedSignedBlindedBeaconBlock, signedAt time.Time, publishMs uint64) error { +func (s *DatabaseService) SaveDeliveredPayload(bidTrace *common.BidTraceV2, signedBlindedBeaconBlock *common.VersionedSignedBlindedBlockRequest, signedAt time.Time, publishMs uint64) error { _signedBlindedBeaconBlock, err := json.Marshal(signedBlindedBeaconBlock) if err != nil { return err @@ -544,7 +541,7 @@ func (s *DatabaseService) DeleteExecutionPayloads(idFirst, idLast uint64) error return err } -func (s *DatabaseService) InsertBuilderDemotion(submitBlockRequest *spec.VersionedSubmitBlockRequest, simError error) error { +func (s *DatabaseService) InsertBuilderDemotion(submitBlockRequest *common.VersionedSubmitBlockRequest, simError error) error { _submitBlockRequest, err := json.Marshal(submitBlockRequest.Capella) if err != nil { return err @@ -577,8 +574,8 @@ func (s *DatabaseService) InsertBuilderDemotion(submitBlockRequest *spec.Version return err } -func (s *DatabaseService) UpdateBuilderDemotion(trace *common.BidTraceV2, signedBlock *consensusspec.VersionedSignedBeaconBlock, signedRegistration *apiv1.SignedValidatorRegistration) error { - _signedBeaconBlock, err := json.Marshal(signedBlock.Capella) +func (s *DatabaseService) UpdateBuilderDemotion(trace *common.BidTraceV2, signedBlock *common.VersionedSignedBlockRequest, signedRegistration *apiv1.SignedValidatorRegistration) error { + _signedBeaconBlock, err := json.Marshal(signedBlock) if err != nil { return err } diff --git a/database/database_test.go b/database/database_test.go index e457cc32..2de0bb31 100644 --- a/database/database_test.go +++ b/database/database_test.go @@ -8,7 +8,8 @@ import ( "time" apiv1 "github.com/attestantio/go-builder-client/api/v1" - "github.com/attestantio/go-eth2-client/spec" + consensusapi "github.com/attestantio/go-eth2-client/api" + consensusspec "github.com/attestantio/go-eth2-client/spec" "github.com/attestantio/go-eth2-client/spec/bellatrix" consensuscapella "github.com/attestantio/go-eth2-client/spec/capella" "github.com/attestantio/go-eth2-client/spec/phase0" @@ -356,8 +357,11 @@ func TestUpdateBuilderDemotion(t *testing.T) { require.Empty(t, demotion.SignedValidatorRegistration.String) // Update demotion with the signedBlock and signedRegistration. - bb := &spec.VersionedSignedBeaconBlock{ - Capella: &consensuscapella.SignedBeaconBlock{}, + bb := &common.VersionedSignedBlockRequest{ + VersionedBlockRequest: consensusapi.VersionedBlockRequest{ + Version: consensusspec.DataVersionCapella, + Capella: &consensuscapella.SignedBeaconBlock{}, + }, } err = db.UpdateBuilderDemotion(bt, bb, &apiv1.SignedValidatorRegistration{}) require.NoError(t, err) diff --git a/database/mockdb.go b/database/mockdb.go index 0c332ec4..8a1f5fd3 100644 --- a/database/mockdb.go +++ b/database/mockdb.go @@ -6,9 +6,6 @@ import ( "time" apiv1 "github.com/attestantio/go-builder-client/api/v1" - "github.com/attestantio/go-builder-client/spec" - consensusapi "github.com/attestantio/go-eth2-client/api" - consensusspec "github.com/attestantio/go-eth2-client/spec" "github.com/flashbots/mev-boost-relay/common" ) @@ -39,7 +36,7 @@ func (db MockDB) GetLatestValidatorRegistrations(timestampOnly bool) ([]*Validat return nil, nil } -func (db MockDB) SaveBuilderBlockSubmission(payload *spec.VersionedSubmitBlockRequest, requestError, validationError error, receivedAt, eligibleAt time.Time, wasSimulated, saveExecPayload bool, profile common.Profile, optimisticSubmission bool) (entry *BuilderBlockSubmissionEntry, err error) { +func (db MockDB) SaveBuilderBlockSubmission(payload *common.VersionedSubmitBlockRequest, requestError, validationError error, receivedAt, eligibleAt time.Time, wasSimulated, saveExecPayload bool, profile common.Profile, optimisticSubmission bool) (entry *BuilderBlockSubmissionEntry, err error) { return nil, nil } @@ -88,7 +85,7 @@ func (db MockDB) GetBuilderSubmissionsBySlots(slotFrom, slotTo uint64) (entries return nil, nil } -func (db MockDB) SaveDeliveredPayload(bidTrace *common.BidTraceV2, signedBlindedBeaconBlock *consensusapi.VersionedSignedBlindedBeaconBlock, signedAt time.Time, publishMs uint64) error { +func (db MockDB) SaveDeliveredPayload(bidTrace *common.BidTraceV2, signedBlindedBeaconBlock *common.VersionedSignedBlindedBlockRequest, signedAt time.Time, publishMs uint64) error { return nil } @@ -156,7 +153,7 @@ func (db MockDB) IncBlockBuilderStatsAfterGetPayload(builderPubkey string) error return nil } -func (db MockDB) InsertBuilderDemotion(submitBlockRequest *spec.VersionedSubmitBlockRequest, simError error) error { +func (db MockDB) InsertBuilderDemotion(submitBlockRequest *common.VersionedSubmitBlockRequest, simError error) error { pubkey, err := submitBlockRequest.Builder() if err != nil { return err @@ -165,7 +162,7 @@ func (db MockDB) InsertBuilderDemotion(submitBlockRequest *spec.VersionedSubmitB return nil } -func (db MockDB) UpdateBuilderDemotion(trace *common.BidTraceV2, signedBlock *consensusspec.VersionedSignedBeaconBlock, signedRegistration *apiv1.SignedValidatorRegistration) error { +func (db MockDB) UpdateBuilderDemotion(trace *common.BidTraceV2, signedBlock *common.VersionedSignedBlockRequest, signedRegistration *apiv1.SignedValidatorRegistration) error { pubkey := trace.BuilderPubkey.String() _, ok := db.Builders[pubkey] if !ok { diff --git a/database/typesconv.go b/database/typesconv.go index 08e205e4..135d0ad8 100644 --- a/database/typesconv.go +++ b/database/typesconv.go @@ -5,7 +5,6 @@ import ( "errors" "github.com/attestantio/go-builder-client/api" - "github.com/attestantio/go-builder-client/spec" consensusspec "github.com/attestantio/go-eth2-client/spec" "github.com/attestantio/go-eth2-client/spec/capella" "github.com/flashbots/mev-boost-relay/common" @@ -13,7 +12,7 @@ import ( var ErrUnsupportedExecutionPayload = errors.New("unsupported execution payload version") -func PayloadToExecPayloadEntry(payload *spec.VersionedSubmitBlockRequest) (*ExecutionPayloadEntry, error) { +func PayloadToExecPayloadEntry(payload *common.VersionedSubmitBlockRequest) (*ExecutionPayloadEntry, error) { var _payload []byte var version string var err error diff --git a/datastore/memcached_test.go b/datastore/memcached_test.go index 415ed3e8..ad54809b 100644 --- a/datastore/memcached_test.go +++ b/datastore/memcached_test.go @@ -33,38 +33,41 @@ var ( ErrNoMemcachedServers = errors.New("no memcached servers specified") ) -func testBuilderSubmitBlockRequest(pubkey phase0.BLSPubKey, signature phase0.BLSSignature, version consensusspec.DataVersion) spec.VersionedSubmitBlockRequest { +func testBuilderSubmitBlockRequest(pubkey phase0.BLSPubKey, signature phase0.BLSSignature, version consensusspec.DataVersion) common.VersionedSubmitBlockRequest { switch version { case consensusspec.DataVersionCapella: - return spec.VersionedSubmitBlockRequest{ - Capella: &capella.SubmitBlockRequest{ - Signature: signature, - Message: &apiv1.BidTrace{ - Slot: 1, - ParentHash: phase0.Hash32{0x01}, - BlockHash: phase0.Hash32{0x09}, - BuilderPubkey: pubkey, - ProposerPubkey: phase0.BLSPubKey{0x03}, - ProposerFeeRecipient: bellatrix.ExecutionAddress{0x04}, - Value: uint256.NewInt(123), - GasLimit: 5002, - GasUsed: 5003, - }, - ExecutionPayload: &capellaspec.ExecutionPayload{ - ParentHash: phase0.Hash32{0x01}, - FeeRecipient: bellatrix.ExecutionAddress{0x02}, - StateRoot: phase0.Root{0x03}, - ReceiptsRoot: phase0.Root{0x04}, - LogsBloom: [256]byte{0x05}, - PrevRandao: phase0.Hash32{0x06}, - BlockNumber: 5001, - GasLimit: 5002, - GasUsed: 5003, - Timestamp: 5004, - ExtraData: []byte{0x07}, - BaseFeePerGas: types.IntToU256(123), - BlockHash: phase0.Hash32{0x09}, - Transactions: []bellatrix.Transaction{}, + return common.VersionedSubmitBlockRequest{ + VersionedSubmitBlockRequest: spec.VersionedSubmitBlockRequest{ + Version: consensusspec.DataVersionCapella, + Capella: &capella.SubmitBlockRequest{ + Signature: signature, + Message: &apiv1.BidTrace{ + Slot: 1, + ParentHash: phase0.Hash32{0x01}, + BlockHash: phase0.Hash32{0x09}, + BuilderPubkey: pubkey, + ProposerPubkey: phase0.BLSPubKey{0x03}, + ProposerFeeRecipient: bellatrix.ExecutionAddress{0x04}, + Value: uint256.NewInt(123), + GasLimit: 5002, + GasUsed: 5003, + }, + ExecutionPayload: &capellaspec.ExecutionPayload{ + ParentHash: phase0.Hash32{0x01}, + FeeRecipient: bellatrix.ExecutionAddress{0x02}, + StateRoot: phase0.Root{0x03}, + ReceiptsRoot: phase0.Root{0x04}, + LogsBloom: [256]byte{0x05}, + PrevRandao: phase0.Hash32{0x06}, + BlockNumber: 5001, + GasLimit: 5002, + GasUsed: 5003, + Timestamp: 5004, + ExtraData: []byte{0x07}, + BaseFeePerGas: types.IntToU256(123), + BlockHash: phase0.Hash32{0x09}, + Transactions: []bellatrix.Transaction{}, + }, }, }, } @@ -73,9 +76,7 @@ func testBuilderSubmitBlockRequest(pubkey phase0.BLSPubKey, signature phase0.BLS case consensusspec.DataVersionUnknown, consensusspec.DataVersionPhase0, consensusspec.DataVersionAltair, consensusspec.DataVersionBellatrix: fallthrough default: - return spec.VersionedSubmitBlockRequest{ - Capella: nil, - } + return common.VersionedSubmitBlockRequest{} } } @@ -110,7 +111,7 @@ func initMemcached(t *testing.T) (mem *Memcached, err error) { // RUN_INTEGRATION_TESTS=1 MEMCACHED_URIS="localhost:11211" go test -v -run ".*Memcached.*" ./... func TestMemcached(t *testing.T) { type test struct { - Input spec.VersionedSubmitBlockRequest + Input common.VersionedSubmitBlockRequest Description string TestSuite func(tc *test) func(*testing.T) } diff --git a/datastore/redis.go b/datastore/redis.go index 4e7091dc..87519037 100644 --- a/datastore/redis.go +++ b/datastore/redis.go @@ -457,7 +457,7 @@ type SaveBidAndUpdateTopBidResponse struct { TimeUpdateFloor time.Duration } -func (r *RedisCache) SaveBidAndUpdateTopBid(ctx context.Context, pipeliner redis.Pipeliner, trace *common.BidTraceV2, payload *spec.VersionedSubmitBlockRequest, getPayloadResponse *api.VersionedExecutionPayload, getHeaderResponse *spec.VersionedSignedBuilderBid, reqReceivedAt time.Time, isCancellationEnabled bool, floorValue *big.Int) (state SaveBidAndUpdateTopBidResponse, err error) { +func (r *RedisCache) SaveBidAndUpdateTopBid(ctx context.Context, pipeliner redis.Pipeliner, trace *common.BidTraceV2, payload *common.VersionedSubmitBlockRequest, getPayloadResponse *api.VersionedExecutionPayload, getHeaderResponse *spec.VersionedSignedBuilderBid, reqReceivedAt time.Time, isCancellationEnabled bool, floorValue *big.Int) (state SaveBidAndUpdateTopBidResponse, err error) { var prevTime, nextTime time.Time prevTime = time.Now() diff --git a/go.mod b/go.mod index 78d80270..04d446ed 100644 --- a/go.mod +++ b/go.mod @@ -122,4 +122,6 @@ retract ( v1.0.0-alpha1 ) -replace github.com/attestantio/go-builder-client => github.com/avalonche/go-builder-client v0.0.0-20230711071258-c1ca05d6e8b7 +replace github.com/attestantio/go-builder-client => github.com/avalonche/go-builder-client v0.0.0-20230731215616-c49675dd2f87 + +replace github.com/attestantio/go-eth2-client => github.com/avalonche/go-eth2-client v0.0.0-20230801235812-ab38c7f8cba1 diff --git a/go.sum b/go.sum index f30052e0..6502a8fd 100644 --- a/go.sum +++ b/go.sum @@ -23,10 +23,10 @@ github.com/alicebob/miniredis/v2 v2.31.0/go.mod h1:UB/T2Uztp7MlFSDakaX1sTXUv5CAS github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/attestantio/go-eth2-client v0.19.9 h1:g5LLX3X7cLC0KS0oai/MtxBOZz3U3QPIX5qryYMxgVE= -github.com/attestantio/go-eth2-client v0.19.9/go.mod h1:TTz7YF6w4z6ahvxKiHuGPn6DbQn7gH6HPuWm/DEQeGE= -github.com/avalonche/go-builder-client v0.0.0-20230711071258-c1ca05d6e8b7 h1:NQt83tMbCmK2V1OuPUUEIudvi8EeULl3iWG3Ht1bdCk= -github.com/avalonche/go-builder-client v0.0.0-20230711071258-c1ca05d6e8b7/go.mod h1:DwesMTOqnCp4u+n3uZ+fWL8wwnSBZVD9VMIVPDR+AZE= +github.com/avalonche/go-builder-client v0.0.0-20230731215616-c49675dd2f87 h1:+GPbCP8XCYteTDwr+e2vWsilPj/7rfXnfAE4ZqjVJQk= +github.com/avalonche/go-builder-client v0.0.0-20230731215616-c49675dd2f87/go.mod h1:8NZx9L/rC7nLhSMbbVR6PXr37tC28wTE4u65n+Pa3BQ= +github.com/avalonche/go-eth2-client v0.0.0-20230801235812-ab38c7f8cba1 h1:jLmNo92ji/g8pdnA+Nuc9b7rTC6BZCv0POhmiFqX9cY= +github.com/avalonche/go-eth2-client v0.0.0-20230801235812-ab38c7f8cba1/go.mod h1:KSVlZSW1A3jUg5H8O89DLtqxgJprRfTtI7k89fLdhu0= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= diff --git a/services/api/service.go b/services/api/service.go index 57c62351..cee39a0d 100644 --- a/services/api/service.go +++ b/services/api/service.go @@ -21,12 +21,7 @@ import ( "time" "github.com/NYTimes/gziphandler" - builderCapella "github.com/attestantio/go-builder-client/api/capella" apiv1 "github.com/attestantio/go-builder-client/api/v1" - "github.com/attestantio/go-builder-client/spec" - consensusapi "github.com/attestantio/go-eth2-client/api" - "github.com/attestantio/go-eth2-client/api/v1/capella" - consensusspec "github.com/attestantio/go-eth2-client/spec" "github.com/attestantio/go-eth2-client/spec/phase0" "github.com/buger/jsonparser" "github.com/flashbots/go-boost-utils/bls" @@ -581,7 +576,7 @@ func (api *RelayAPI) simulateBlock(ctx context.Context, opts blockSimOptions) (r return nil, nil } -func (api *RelayAPI) demoteBuilder(pubkey string, req *spec.VersionedSubmitBlockRequest, simError error) { +func (api *RelayAPI) demoteBuilder(pubkey string, req *common.VersionedSubmitBlockRequest, simError error) { builderEntry, ok := api.blockBuildersCache[pubkey] if !ok { api.log.Warnf("builder %v not in the builder cache", pubkey) @@ -1230,10 +1225,8 @@ func (api *RelayAPI) handleGetPayload(w http.ResponseWriter, req *http.Request) } // Decode payload - payload := new(consensusapi.VersionedSignedBlindedBeaconBlock) - // TODO: add deneb support. - payload.Capella = new(capella.SignedBlindedBeaconBlock) - if err := json.NewDecoder(bytes.NewReader(body)).Decode(payload.Capella); err != nil { + payload := new(common.VersionedSignedBlindedBlockRequest) + if err := json.NewDecoder(bytes.NewReader(body)).Decode(payload); err != nil { log.WithError(err).Warn("failed to decode capella getPayload request") api.RespondError(w, http.StatusBadRequest, "failed to decode capella payload") return @@ -1591,7 +1584,17 @@ func (api *RelayAPI) checkSubmissionPayloadAttrs(w http.ResponseWriter, log *log return true } -func (api *RelayAPI) checkSubmissionSlotDetails(w http.ResponseWriter, log *logrus.Entry, headSlot uint64, submission *common.BlockSubmissionInfo) bool { +func (api *RelayAPI) checkSubmissionSlotDetails(w http.ResponseWriter, log *logrus.Entry, headSlot uint64, payload *common.VersionedSubmitBlockRequest, submission *common.BlockSubmissionInfo) bool { + if hasReachedFork(submission.Slot, api.denebEpoch) && payload.Deneb == nil { + log.Info("rejecting submission - non deneb payload for deneb fork") + api.RespondError(w, http.StatusBadRequest, "not deneb payload") + return false + } else if hasReachedFork(submission.Slot, api.capellaEpoch) && payload.Capella == nil { + log.Info("rejecting submission - non capella payload for capella fork") + api.RespondError(w, http.StatusBadRequest, "not capella payload") + return false + } + if submission.Slot <= headSlot { log.Info("submitNewBlock failed: submission for past slot") api.RespondError(w, http.StatusBadRequest, "submission for past slot") @@ -1794,20 +1797,17 @@ func (api *RelayAPI) handleSubmitNewBlock(w http.ResponseWriter, req *http.Reque return } - payload := &spec.VersionedSubmitBlockRequest{ //nolint:exhaustruct - Version: consensusspec.DataVersionCapella, - } - payload.Capella = new(builderCapella.SubmitBlockRequest) + payload := new(common.VersionedSubmitBlockRequest) // Check for SSZ encoding contentType := req.Header.Get("Content-Type") if contentType == "application/octet-stream" { log = log.WithField("reqContentType", "ssz") - if err = payload.Capella.UnmarshalSSZ(requestPayloadBytes); err != nil { + if err = payload.UnmarshalSSZ(requestPayloadBytes); err != nil { log.WithError(err).Warn("could not decode payload - SSZ") // SSZ decoding failed. try JSON as fallback (some builders used octet-stream for json before) - if err2 := json.Unmarshal(requestPayloadBytes, payload.Capella); err2 != nil { + if err2 := json.Unmarshal(requestPayloadBytes, payload); err2 != nil { log.WithError(fmt.Errorf("%w / %w", err, err2)).Warn("could not decode payload - SSZ or JSON") api.RespondError(w, http.StatusBadRequest, err.Error()) return @@ -1818,7 +1818,7 @@ func (api *RelayAPI) handleSubmitNewBlock(w http.ResponseWriter, req *http.Reque } } else { log = log.WithField("reqContentType", "json") - if err := json.Unmarshal(requestPayloadBytes, payload.Capella); err != nil { + if err := json.Unmarshal(requestPayloadBytes, payload); err != nil { log.WithError(err).Warn("could not decode payload - JSON") api.RespondError(w, http.StatusBadRequest, err.Error()) return @@ -1850,7 +1850,7 @@ func (api *RelayAPI) handleSubmitNewBlock(w http.ResponseWriter, req *http.Reque "isLargeRequest": isLargeRequest, }) - ok := api.checkSubmissionSlotDetails(w, log, headSlot, submission) + ok := api.checkSubmissionSlotDetails(w, log, headSlot, payload, submission) if !ok { return } diff --git a/services/api/service_test.go b/services/api/service_test.go index 553e1c5b..015c8dbf 100644 --- a/services/api/service_test.go +++ b/services/api/service_test.go @@ -310,7 +310,7 @@ func TestDataApiGetDataProposerPayloadDelivered(t *testing.T) { func TestBuilderSubmitBlockSSZ(t *testing.T) { requestPayloadJSONBytes := common.LoadGzippedBytes(t, "../../testdata/submitBlockPayloadCapella_Goerli.json.gz") - req := new(spec.VersionedSubmitBlockRequest) + req := new(common.VersionedSubmitBlockRequest) req.Capella = new(builderCapella.SubmitBlockRequest) err := json.Unmarshal(requestPayloadJSONBytes, req.Capella) require.NoError(t, err) @@ -365,7 +365,7 @@ func TestBuilderSubmitBlock(t *testing.T) { } // Prepare the request payload - req := new(spec.VersionedSubmitBlockRequest) + req := new(common.VersionedSubmitBlockRequest) req.Capella = new(builderCapella.SubmitBlockRequest) requestPayloadJSONBytes := common.LoadGzippedBytes(t, payloadJSONFilename) require.NoError(t, err) @@ -424,7 +424,7 @@ func TestCheckSubmissionFeeRecipient(t *testing.T) { cases := []struct { description string slotDuty *common.BuilderGetValidatorsResponseEntry - payload *spec.VersionedSubmitBlockRequest + payload *common.VersionedSubmitBlockRequest expectOk bool expectGasLimit uint64 }{ @@ -438,14 +438,16 @@ func TestCheckSubmissionFeeRecipient(t *testing.T) { }, }, }, - payload: &spec.VersionedSubmitBlockRequest{ - Version: consensusspec.DataVersionCapella, - Capella: &builderCapella.SubmitBlockRequest{ - Message: &apiv1.BidTrace{ - Slot: testSlot, - ProposerFeeRecipient: testAddress, + payload: &common.VersionedSubmitBlockRequest{ + VersionedSubmitBlockRequest: spec.VersionedSubmitBlockRequest{ + Version: consensusspec.DataVersionCapella, + Capella: &builderCapella.SubmitBlockRequest{ + Message: &apiv1.BidTrace{ + Slot: testSlot, + ProposerFeeRecipient: testAddress, + }, + ExecutionPayload: &capella.ExecutionPayload{}, }, - ExecutionPayload: &capella.ExecutionPayload{}, }, }, expectOk: true, @@ -454,13 +456,15 @@ func TestCheckSubmissionFeeRecipient(t *testing.T) { { description: "failure_nil_slot_duty", slotDuty: nil, - payload: &spec.VersionedSubmitBlockRequest{ - Version: consensusspec.DataVersionCapella, - Capella: &builderCapella.SubmitBlockRequest{ - Message: &apiv1.BidTrace{ - Slot: testSlot, + payload: &common.VersionedSubmitBlockRequest{ + VersionedSubmitBlockRequest: spec.VersionedSubmitBlockRequest{ + Version: consensusspec.DataVersionCapella, + Capella: &builderCapella.SubmitBlockRequest{ + Message: &apiv1.BidTrace{ + Slot: testSlot, + }, + ExecutionPayload: &capella.ExecutionPayload{}, }, - ExecutionPayload: &capella.ExecutionPayload{}, }, }, expectOk: false, @@ -476,14 +480,16 @@ func TestCheckSubmissionFeeRecipient(t *testing.T) { }, }, }, - payload: &spec.VersionedSubmitBlockRequest{ - Version: consensusspec.DataVersionCapella, - Capella: &builderCapella.SubmitBlockRequest{ - Message: &apiv1.BidTrace{ - Slot: testSlot, - ProposerFeeRecipient: testAddress2, + payload: &common.VersionedSubmitBlockRequest{ + VersionedSubmitBlockRequest: spec.VersionedSubmitBlockRequest{ + Version: consensusspec.DataVersionCapella, + Capella: &builderCapella.SubmitBlockRequest{ + Message: &apiv1.BidTrace{ + Slot: testSlot, + ProposerFeeRecipient: testAddress2, + }, + ExecutionPayload: &capella.ExecutionPayload{}, }, - ExecutionPayload: &capella.ExecutionPayload{}, }, }, expectOk: false, @@ -522,7 +528,7 @@ func TestCheckSubmissionPayloadAttrs(t *testing.T) { cases := []struct { description string attrs payloadAttributesHelper - payload *spec.VersionedSubmitBlockRequest + payload *common.VersionedSubmitBlockRequest expectOk bool }{ { @@ -535,20 +541,22 @@ func TestCheckSubmissionPayloadAttrs(t *testing.T) { PrevRandao: testPrevRandao, }, }, - payload: &spec.VersionedSubmitBlockRequest{ - Version: consensusspec.DataVersionCapella, - Capella: &builderCapella.SubmitBlockRequest{ - ExecutionPayload: &capella.ExecutionPayload{ - PrevRandao: prevRandao, - Withdrawals: []*capella.Withdrawal{ - { - Index: 989694, + payload: &common.VersionedSubmitBlockRequest{ + VersionedSubmitBlockRequest: spec.VersionedSubmitBlockRequest{ + Version: consensusspec.DataVersionCapella, + Capella: &builderCapella.SubmitBlockRequest{ + ExecutionPayload: &capella.ExecutionPayload{ + PrevRandao: prevRandao, + Withdrawals: []*capella.Withdrawal{ + { + Index: 989694, + }, }, }, - }, - Message: &apiv1.BidTrace{ - Slot: testSlot, - ParentHash: parentHash, + Message: &apiv1.BidTrace{ + Slot: testSlot, + ParentHash: parentHash, + }, }, }, }, @@ -559,13 +567,15 @@ func TestCheckSubmissionPayloadAttrs(t *testing.T) { attrs: payloadAttributesHelper{ slot: testSlot, }, - payload: &spec.VersionedSubmitBlockRequest{ - Version: consensusspec.DataVersionCapella, - Capella: &builderCapella.SubmitBlockRequest{ - Message: &apiv1.BidTrace{ - Slot: testSlot + 1, // submission for a future slot + payload: &common.VersionedSubmitBlockRequest{ + VersionedSubmitBlockRequest: spec.VersionedSubmitBlockRequest{ + Version: consensusspec.DataVersionCapella, + Capella: &builderCapella.SubmitBlockRequest{ + Message: &apiv1.BidTrace{ + Slot: testSlot + 1, // submission for a future slot + }, + ExecutionPayload: &capella.ExecutionPayload{}, }, - ExecutionPayload: &capella.ExecutionPayload{}, }, }, expectOk: false, @@ -578,15 +588,17 @@ func TestCheckSubmissionPayloadAttrs(t *testing.T) { PrevRandao: testPrevRandao, }, }, - payload: &spec.VersionedSubmitBlockRequest{ - Version: consensusspec.DataVersionCapella, - Capella: &builderCapella.SubmitBlockRequest{ - Message: &apiv1.BidTrace{ - Slot: testSlot, - ParentHash: parentHash, - }, - ExecutionPayload: &capella.ExecutionPayload{ - PrevRandao: [32]byte(parentHash), // use a different hash to cause an error + payload: &common.VersionedSubmitBlockRequest{ + VersionedSubmitBlockRequest: spec.VersionedSubmitBlockRequest{ + Version: consensusspec.DataVersionCapella, + Capella: &builderCapella.SubmitBlockRequest{ + Message: &apiv1.BidTrace{ + Slot: testSlot, + ParentHash: parentHash, + }, + ExecutionPayload: &capella.ExecutionPayload{ + PrevRandao: [32]byte(parentHash), // use a different hash to cause an error + }, }, }, }, @@ -600,16 +612,18 @@ func TestCheckSubmissionPayloadAttrs(t *testing.T) { PrevRandao: testPrevRandao, }, }, - payload: &spec.VersionedSubmitBlockRequest{ - Version: consensusspec.DataVersionCapella, - Capella: &builderCapella.SubmitBlockRequest{ - Message: &apiv1.BidTrace{ - Slot: testSlot, - ParentHash: parentHash, - }, - ExecutionPayload: &capella.ExecutionPayload{ - PrevRandao: [32]byte(prevRandao), - Withdrawals: nil, // set to nil to cause an error + payload: &common.VersionedSubmitBlockRequest{ + VersionedSubmitBlockRequest: spec.VersionedSubmitBlockRequest{ + Version: consensusspec.DataVersionCapella, + Capella: &builderCapella.SubmitBlockRequest{ + Message: &apiv1.BidTrace{ + Slot: testSlot, + ParentHash: parentHash, + }, + ExecutionPayload: &capella.ExecutionPayload{ + PrevRandao: [32]byte(prevRandao), + Withdrawals: nil, // set to nil to cause an error + }, }, }, }, @@ -625,20 +639,22 @@ func TestCheckSubmissionPayloadAttrs(t *testing.T) { PrevRandao: testPrevRandao, }, }, - payload: &spec.VersionedSubmitBlockRequest{ - Version: consensusspec.DataVersionCapella, - Capella: &builderCapella.SubmitBlockRequest{ - ExecutionPayload: &capella.ExecutionPayload{ - PrevRandao: [32]byte(prevRandao), - Withdrawals: []*capella.Withdrawal{ - { - Index: 989694, + payload: &common.VersionedSubmitBlockRequest{ + VersionedSubmitBlockRequest: spec.VersionedSubmitBlockRequest{ + Version: consensusspec.DataVersionCapella, + Capella: &builderCapella.SubmitBlockRequest{ + ExecutionPayload: &capella.ExecutionPayload{ + PrevRandao: [32]byte(prevRandao), + Withdrawals: []*capella.Withdrawal{ + { + Index: 989694, + }, }, }, - }, - Message: &apiv1.BidTrace{ - Slot: testSlot, - ParentHash: parentHash, + Message: &apiv1.BidTrace{ + Slot: testSlot, + ParentHash: parentHash, + }, }, }, }, @@ -666,19 +682,21 @@ func TestCheckSubmissionPayloadAttrs(t *testing.T) { func TestCheckSubmissionSlotDetails(t *testing.T) { cases := []struct { description string - payload *spec.VersionedSubmitBlockRequest + payload *common.VersionedSubmitBlockRequest expectOk bool }{ { description: "success", - payload: &spec.VersionedSubmitBlockRequest{ - Version: consensusspec.DataVersionCapella, - Capella: &builderCapella.SubmitBlockRequest{ - ExecutionPayload: &capella.ExecutionPayload{ - Timestamp: testSlot * common.SecondsPerSlot, - }, - Message: &apiv1.BidTrace{ - Slot: testSlot, + payload: &common.VersionedSubmitBlockRequest{ + VersionedSubmitBlockRequest: spec.VersionedSubmitBlockRequest{ + Version: consensusspec.DataVersionCapella, + Capella: &builderCapella.SubmitBlockRequest{ + ExecutionPayload: &capella.ExecutionPayload{ + Timestamp: testSlot * common.SecondsPerSlot, + }, + Message: &apiv1.BidTrace{ + Slot: testSlot, + }, }, }, }, @@ -686,27 +704,31 @@ func TestCheckSubmissionSlotDetails(t *testing.T) { }, { description: "failure_past_slot", - payload: &spec.VersionedSubmitBlockRequest{ - Version: consensusspec.DataVersionCapella, - Capella: &builderCapella.SubmitBlockRequest{ - Message: &apiv1.BidTrace{ - Slot: testSlot - 1, // use old slot to cause error + payload: &common.VersionedSubmitBlockRequest{ + VersionedSubmitBlockRequest: spec.VersionedSubmitBlockRequest{ + Version: consensusspec.DataVersionCapella, + Capella: &builderCapella.SubmitBlockRequest{ + Message: &apiv1.BidTrace{ + Slot: testSlot - 1, // use old slot to cause error + }, + ExecutionPayload: &capella.ExecutionPayload{}, }, - ExecutionPayload: &capella.ExecutionPayload{}, }, }, expectOk: false, }, { description: "failure_wrong_timestamp", - payload: &spec.VersionedSubmitBlockRequest{ - Version: consensusspec.DataVersionCapella, - Capella: &builderCapella.SubmitBlockRequest{ - ExecutionPayload: &capella.ExecutionPayload{ - Timestamp: testSlot*common.SecondsPerSlot - 1, // use wrong timestamp to cause error - }, - Message: &apiv1.BidTrace{ - Slot: testSlot, + payload: &common.VersionedSubmitBlockRequest{ + VersionedSubmitBlockRequest: spec.VersionedSubmitBlockRequest{ + Version: consensusspec.DataVersionCapella, + Capella: &builderCapella.SubmitBlockRequest{ + ExecutionPayload: &capella.ExecutionPayload{ + Timestamp: testSlot*common.SecondsPerSlot - 1, // use wrong timestamp to cause error + }, + Message: &apiv1.BidTrace{ + Slot: testSlot, + }, }, }, }, @@ -723,7 +745,7 @@ func TestCheckSubmissionSlotDetails(t *testing.T) { log := logrus.NewEntry(logger) submission, err := common.GetBlockSubmissionInfo(tc.payload) require.NoError(t, err) - ok := backend.relay.checkSubmissionSlotDetails(w, log, headSlot, submission) + ok := backend.relay.checkSubmissionSlotDetails(w, log, headSlot, tc.payload, submission) require.Equal(t, tc.expectOk, ok) }) } diff --git a/services/api/utils.go b/services/api/utils.go index 0b67d06b..889ac74f 100644 --- a/services/api/utils.go +++ b/services/api/utils.go @@ -4,8 +4,6 @@ import ( "errors" "github.com/attestantio/go-builder-client/api" - "github.com/attestantio/go-builder-client/spec" - consensusapi "github.com/attestantio/go-eth2-client/api" "github.com/attestantio/go-eth2-client/spec/capella" "github.com/attestantio/go-eth2-client/spec/phase0" utilcapella "github.com/attestantio/go-eth2-client/util/capella" @@ -25,7 +23,7 @@ var ( ErrHeaderHTRMismatch = errors.New("beacon-block and payload header mismatch") ) -func SanityCheckBuilderBlockSubmission(payload *spec.VersionedSubmitBlockRequest) error { +func SanityCheckBuilderBlockSubmission(payload *common.VersionedSubmitBlockRequest) error { submission, err := common.GetBlockSubmissionInfo(payload) if err != nil { return err @@ -49,7 +47,7 @@ func ComputeWithdrawalsRoot(w []*capella.Withdrawal) (phase0.Root, error) { return withdrawals.HashTreeRoot() } -func EqExecutionPayloadToHeader(bb *consensusapi.VersionedSignedBlindedBeaconBlock, payload *api.VersionedExecutionPayload) error { +func EqExecutionPayloadToHeader(bb *common.VersionedSignedBlindedBlockRequest, payload *api.VersionedExecutionPayload) error { if bb.Capella != nil { // process Capella beacon block if payload.Capella == nil { return ErrPayloadMismatchCapella @@ -90,12 +88,12 @@ func hasReachedFork(slot, forkEpoch uint64) bool { return currentEpoch >= forkEpoch } -func checkProposerSignature(block *consensusapi.VersionedSignedBlindedBeaconBlock, domain phase0.Domain, pubKey []byte) (bool, error) { +func checkProposerSignature(block *common.VersionedSignedBlindedBlockRequest, domain phase0.Domain, pubKey []byte) (bool, error) { root, err := block.Root() if err != nil { return false, err } - sig, err := block.Signature() + sig, err := block.BeaconBlockSignature() if err != nil { return false, err } diff --git a/testdata/signedBeaconBlock_Goerli.json.gz b/testdata/signedBeaconBlock_Goerli.json.gz new file mode 100644 index 00000000..9700c63c Binary files /dev/null and b/testdata/signedBeaconBlock_Goerli.json.gz differ diff --git a/testdata/signedBlindedBeaconBlock_Goerli.json.gz b/testdata/signedBlindedBeaconBlock_Goerli.json.gz new file mode 100644 index 00000000..0c2df95f Binary files /dev/null and b/testdata/signedBlindedBeaconBlock_Goerli.json.gz differ