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

Add /eth/v2/validator/aggregate_attestation #14481

Open
wants to merge 21 commits into
base: develop
Choose a base branch
from

Conversation

saolyn
Copy link
Contributor

@saolyn saolyn commented Sep 25, 2024

What type of PR is this?

Other

What does this PR do? Why is it needed?

Beacon API Electra alignment, add missing endpoint for /eth/v2/validator/aggregate_attestation.
As described in the spec https://ethereum.github.io/beacon-APIs/?urls.primaryName=dev#/Validator/getAggregatedAttestationV2

Which issues(s) does this PR fix?

Part of #14476

Other notes for review

Acknowledgements

  • I have read CONTRIBUTING.md.
  • I have made an appropriate entry to CHANGELOG.md.
  • I have added a description to this PR with sufficient context for reviewers to understand this PR.

@saolyn saolyn marked this pull request as ready for review September 25, 2024 15:45
@saolyn saolyn requested a review from a team as a code owner September 25, 2024 15:45
return nil
}
}
if match == nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

this should be moved inside the first match check right?

Copy link
Contributor

Choose a reason for hiding this comment

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

doesn't matter too much because we assign to an existing variable

func matchingAtt(atts []ethpbalpha.Att, slot primitives.Slot, attDataRoot []byte) (ethpbalpha.Att, error) {
// GetAggregateAttestationV2 aggregates all attestations matching the given attestation data root and slot, returning the aggregated result.
func (s *Server) GetAggregateAttestationV2(w http.ResponseWriter, r *http.Request) {
_, span := trace.StartSpan(r.Context(), "validator.GetAggregateAttestation")
Copy link
Contributor

Choose a reason for hiding this comment

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

maybe should update validator.GetAggregateAttestationV2

CHANGELOG.md Outdated Show resolved Hide resolved
api/server/structs/endpoints_validator.go Outdated Show resolved Hide resolved
if !ok {
return
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change

if !ok {
return
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change

return nil
}
}
if match == nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

doesn't matter too much because we assign to an existing variable

beacon-chain/rpc/eth/validator/handlers.go Outdated Show resolved Hide resolved
beacon-chain/rpc/eth/validator/handlers.go Outdated Show resolved Hide resolved
beacon-chain/rpc/eth/validator/handlers.go Outdated Show resolved Hide resolved
@rkapka
Copy link
Contributor

rkapka commented Oct 2, 2024

I just noticed that this endpoint never worked correctly. The description says

Aggregates all attestations matching given attestation data root and slot.

This means that if we don't have a matching aggregated attestation, but we have a matching unaggregated one, we have to aggregate these attestations. I think this is a good moment to fix this.

beacon-chain/rpc/eth/validator/handlers.go Outdated Show resolved Hide resolved
beacon-chain/rpc/eth/validator/handlers.go Outdated Show resolved Hide resolved
beacon-chain/rpc/eth/validator/handlers.go Outdated Show resolved Hide resolved
beacon-chain/rpc/eth/validator/handlers.go Outdated Show resolved Hide resolved
@@ -52,7 +53,12 @@ func (c *beaconApiValidatorClient) submitAggregateSelectionProof(
return nil, err
}

aggregatedAttestation, err := convertAttestationToProto(aggregateAttestationResponse.Data)
var attData *ethpb.Attestation // Replace with your appropriate struct
Copy link
Contributor

Choose a reason for hiding this comment

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

You should unmarshal into the API type, not the protobuf one

Copy link
Contributor Author

@saolyn saolyn Oct 10, 2024

Choose a reason for hiding this comment

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

Not sure how to get it working with the API type

beacon-chain/rpc/eth/validator/handlers.go Outdated Show resolved Hide resolved
Comment on lines 81 to 92
_, attDataRoot, ok := shared.HexFromQuery(w, r, "attestation_data_root", fieldparams.RootLength, true)
if !ok {
return
}
_, slot, ok := shared.UintFromQuery(w, r, "slot", true)
if !ok {
return
}
_, index, ok := shared.UintFromQuery(w, r, "committee_index", true)
if !ok {
return
}
Copy link
Member

Choose a reason for hiding this comment

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

These should return a 400 / bad request since they are required fields.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

They already do, within shared.UintFromQuery we have ValidateUint which handles the http error, same thing applies to shared.HexFromQuery

beacon-chain/rpc/eth/validator/handlers.go Outdated Show resolved Hide resolved
}

func matchingAtt(atts []ethpbalpha.Att, slot primitives.Slot, attDataRoot []byte) (ethpbalpha.Att, error) {
func matchingAtt(atts []ethpbalpha.Att, slot primitives.Slot, attDataRoot []byte, index string) (ethpbalpha.Att, error) {
Copy link
Member

Choose a reason for hiding this comment

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

If there are multiple that match, return the best one by most CommitteeBitsVal().Count(), assuming they cannot be further aggregated.

Or consider returning all matching atts.

func matchingAtts(atts []ethpbalpha.Att, slot primitives.Slot, attDataRoot []byte, index string) ([]ethpbalpha.Att, error)

httputil.HandleError(w, "No matching attestation found", http.StatusNotFound)
return nil
}
_, err = attestations.Aggregate([]ethpbalpha.Att{match})
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
_, err = attestations.Aggregate([]ethpbalpha.Att{match})
agg, err = attestations.Aggregate([]ethpbalpha.Att{matches})
...
return agg[0]

If they cannot be aggregate to just one (len(agg) == 1), then return best by committee bits count.

}

func matchingAtt(atts []ethpbalpha.Att, slot primitives.Slot, attDataRoot []byte) (ethpbalpha.Att, error) {
func matchingAtts(atts []ethpbalpha.Att, slot primitives.Slot, attDataRoot []byte, index primitives.CommitteeIndex) ([]ethpbalpha.Att, error) {
if len(atts) == 0 {
Copy link
Contributor

Choose a reason for hiding this comment

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

So that we don't panic in the declaration of postElectra

}
typedAgg, ok := agg.(*ethpbalpha.Attestation)
if !ok {
httputil.HandleError(w, fmt.Sprintf("Attestation is not of type %T", &ethpbalpha.Attestation{}), http.StatusInternalServerError)
Copy link
Contributor

Choose a reason for hiding this comment

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

%T with an empty struct is nicer in my opinion because if the type name changes, you will get a compiler error


match, err := matchingAtts(s.AttestationsPool.AggregatedAttestations(), slot, attDataRoot, index)
if err != nil {
httputil.HandleError(w, "Could not get matching attestation: "+err.Error(), http.StatusInternalServerError)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nit

Suggested change
httputil.HandleError(w, "Could not get matching attestation: "+err.Error(), http.StatusInternalServerError)
httputil.HandleError(w, "Could not get matching attestations: "+err.Error(), http.StatusInternalServerError)

Copy link
Contributor

@rkapka rkapka left a comment

Choose a reason for hiding this comment

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

tests are incorrect

},
}
}

func TestGetAggregateAttestation_SameSlotAndRoot_ReturnMostAggregationBits(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.

This test can be removed because it's a duplicate of one of the new test cases

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants