Skip to content

Commit

Permalink
*: support electra in existing codebase; tests (#3487)
Browse files Browse the repository at this point in the history
* Add electra version support in all switch cases

* Add more electra tests
  • Loading branch information
KaloyanTanev committed Jan 31, 2025
1 parent 21907ff commit 695d1df
Show file tree
Hide file tree
Showing 16 changed files with 2,291 additions and 433 deletions.
126 changes: 99 additions & 27 deletions app/eth2wrap/eth2wrap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
eth2api "github.com/attestantio/go-eth2-client/api"
eth2v1 "github.com/attestantio/go-eth2-client/api/v1"
eth2spec "github.com/attestantio/go-eth2-client/spec"
eth2e "github.com/attestantio/go-eth2-client/spec/electra"
eth2p0 "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -358,37 +359,108 @@ func TestCtxCancel(t *testing.T) {
}
}

func TestBlockAttestations(t *testing.T) {
atts := []*eth2spec.VersionedAttestation{
testutil.RandomDenebVersionedAttestation(),
testutil.RandomDenebVersionedAttestation(),
}
func TestBlockAttestationsV2(t *testing.T) {
phase0Att1 := testutil.RandomPhase0Attestation()
phase0Att2 := testutil.RandomPhase0Attestation()
electraAtt1 := testutil.RandomElectraAttestation()
electraAtt2 := testutil.RandomElectraAttestation()

statusCode := http.StatusOK
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, http.MethodGet, r.Method)
require.Equal(t, "/eth/v2/beacon/blocks/head/attestations", r.URL.Path)
b, err := json.Marshal(struct {
Data []*eth2p0.Attestation
}{
Data: []*eth2p0.Attestation{atts[0].Deneb, atts[1].Deneb},
})
require.NoError(t, err)
tests := []struct {
version string
attestations []*eth2spec.VersionedAttestation
serverJSONStruct any
expErr string
}{
{
version: "electra",
attestations: []*eth2spec.VersionedAttestation{
{Version: eth2spec.DataVersionElectra, Electra: electraAtt1},
{Version: eth2spec.DataVersionElectra, Electra: electraAtt2},
},
serverJSONStruct: struct{ Data []*eth2e.Attestation }{Data: []*eth2e.Attestation{electraAtt1, electraAtt2}},
expErr: "",
},
{
version: "deneb",
attestations: []*eth2spec.VersionedAttestation{
{Version: eth2spec.DataVersionDeneb, Deneb: phase0Att1},
{Version: eth2spec.DataVersionDeneb, Deneb: phase0Att2},
},
serverJSONStruct: struct{ Data []*eth2p0.Attestation }{Data: []*eth2p0.Attestation{phase0Att1, phase0Att2}},
expErr: "",
},
{
version: "capella",
attestations: []*eth2spec.VersionedAttestation{
{Version: eth2spec.DataVersionCapella, Capella: phase0Att1},
{Version: eth2spec.DataVersionCapella, Capella: phase0Att2},
},
serverJSONStruct: struct{ Data []*eth2p0.Attestation }{Data: []*eth2p0.Attestation{phase0Att1, phase0Att2}},
expErr: "",
},
{
version: "bellatrix",
attestations: []*eth2spec.VersionedAttestation{
{Version: eth2spec.DataVersionBellatrix, Bellatrix: phase0Att1},
{Version: eth2spec.DataVersionBellatrix, Bellatrix: phase0Att2},
},
serverJSONStruct: struct{ Data []*eth2p0.Attestation }{Data: []*eth2p0.Attestation{phase0Att1, phase0Att2}},
expErr: "",
},
{
version: "altair",
attestations: []*eth2spec.VersionedAttestation{
{Version: eth2spec.DataVersionAltair, Altair: phase0Att1},
{Version: eth2spec.DataVersionAltair, Altair: phase0Att2},
},
serverJSONStruct: struct{ Data []*eth2p0.Attestation }{Data: []*eth2p0.Attestation{phase0Att1, phase0Att2}},
expErr: "",
},
{
version: "phase0",
attestations: []*eth2spec.VersionedAttestation{
{Version: eth2spec.DataVersionPhase0, Phase0: phase0Att1},
{Version: eth2spec.DataVersionPhase0, Phase0: phase0Att2},
},
serverJSONStruct: struct{ Data []*eth2p0.Attestation }{Data: []*eth2p0.Attestation{phase0Att1, phase0Att2}},
expErr: "",
},
{
version: "unknown version",
attestations: nil,
serverJSONStruct: struct{ Data []*eth2p0.Attestation }{Data: []*eth2p0.Attestation{phase0Att1, phase0Att2}},
expErr: "failed to get consensus version",
},
}
for _, test := range tests {
t.Run(test.version, func(t *testing.T) {
statusCode := http.StatusOK
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, http.MethodGet, r.Method)
require.Equal(t, "/eth/v2/beacon/blocks/head/attestations", r.URL.Path)
b, err := json.Marshal(test.serverJSONStruct)
require.NoError(t, err)

w.Header().Add("Eth-Consensus-Version", "deneb")
w.WriteHeader(statusCode)
_, _ = w.Write(b)
}))
w.Header().Add("Eth-Consensus-Version", test.version)
w.WriteHeader(statusCode)
_, _ = w.Write(b)
}))

cl := eth2wrap.NewHTTPAdapterForT(t, srv.URL, time.Hour)
resp, err := cl.BlockAttestationsV2(context.Background(), "head")
require.NoError(t, err)
require.Equal(t, atts, resp)
cl := eth2wrap.NewHTTPAdapterForT(t, srv.URL, time.Hour)
resp, err := cl.BlockAttestationsV2(context.Background(), "head")
if test.expErr != "" {
require.ErrorContains(t, err, test.expErr)
} else {
require.NoError(t, err)
}
require.Equal(t, test.attestations, resp)

statusCode = http.StatusNotFound
resp, err = cl.BlockAttestationsV2(context.Background(), "head")
require.NoError(t, err)
require.Empty(t, resp)
statusCode = http.StatusNotFound
resp, err = cl.BlockAttestationsV2(context.Background(), "head")
require.NoError(t, err)
require.Empty(t, resp)
})
}
}

// TestOneError tests the case where one of the servers returns errors.
Expand Down
13 changes: 13 additions & 0 deletions app/eth2wrap/synthproposer.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
eth2api "github.com/attestantio/go-eth2-client/api"
eth2v1 "github.com/attestantio/go-eth2-client/api/v1"
eth2deneb "github.com/attestantio/go-eth2-client/api/v1/deneb"
eth2electra "github.com/attestantio/go-eth2-client/api/v1/electra"
eth2spec "github.com/attestantio/go-eth2-client/spec"
"github.com/attestantio/go-eth2-client/spec/bellatrix"
eth2p0 "github.com/attestantio/go-eth2-client/spec/phase0"
Expand Down Expand Up @@ -174,6 +175,14 @@ func (h *synthWrapper) syntheticProposal(ctx context.Context, slot eth2p0.Slot,
proposal.Deneb.Block.ProposerIndex = vIdx
proposal.Deneb.Block.Body.ExecutionPayload.FeeRecipient = feeRecipient
proposal.Deneb.Block.Body.ExecutionPayload.Transactions = fraction(proposal.Deneb.Block.Body.ExecutionPayload.Transactions)
case eth2spec.DataVersionElectra:
proposal.Electra = &eth2electra.BlockContents{}
proposal.Electra.Block = signedBlock.Electra.Message
proposal.Electra.Block.Body.Graffiti = GetSyntheticGraffiti()
proposal.Electra.Block.Slot = slot
proposal.Electra.Block.ProposerIndex = vIdx
proposal.Electra.Block.Body.ExecutionPayload.FeeRecipient = feeRecipient
proposal.Electra.Block.Body.ExecutionPayload.Transactions = fraction(proposal.Electra.Block.Body.ExecutionPayload.Transactions)
default:
return nil, errors.New("unsupported proposal version")
}
Expand Down Expand Up @@ -225,6 +234,8 @@ func IsSyntheticBlindedBlock(block *eth2api.VersionedSignedBlindedProposal) bool
graffiti = block.Capella.Message.Body.Graffiti
case eth2spec.DataVersionDeneb:
graffiti = block.Deneb.Message.Body.Graffiti
case eth2spec.DataVersionElectra:
graffiti = block.Electra.Message.Body.Graffiti
default:
return false
}
Expand All @@ -246,6 +257,8 @@ func IsSyntheticProposal(block *eth2api.VersionedSignedProposal) bool {
graffiti = block.Capella.Message.Body.Graffiti
case eth2spec.DataVersionDeneb:
graffiti = block.Deneb.SignedBlock.Message.Body.Graffiti
case eth2spec.DataVersionElectra:
graffiti = block.Electra.SignedBlock.Message.Body.Graffiti
default:
return false
}
Expand Down
Loading

0 comments on commit 695d1df

Please sign in to comment.