Skip to content

Commit

Permalink
Merge pull request #136 from jtraglia/pass-electra-tests
Browse files Browse the repository at this point in the history
Fix problems with new Electra structs
  • Loading branch information
mcdee authored May 8, 2024
2 parents 4654a8b + c7ad6f5 commit 3117883
Show file tree
Hide file tree
Showing 27 changed files with 1,365 additions and 54 deletions.
42 changes: 37 additions & 5 deletions api/versionedblockrequest.go
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ func (v *VersionedBlockRequest) StateRoot() (phase0.Root, error) {
}

// AttesterSlashings returns the attester slashings of the beacon block.
func (v *VersionedBlockRequest) AttesterSlashings() ([]*phase0.AttesterSlashing, error) {
func (v *VersionedBlockRequest) AttesterSlashings() ([]spec.VersionedAttesterSlashing, error) {
switch v.Version {
case spec.DataVersionBellatrix:
if v.Bellatrix == nil ||
Expand All @@ -342,31 +342,63 @@ func (v *VersionedBlockRequest) AttesterSlashings() ([]*phase0.AttesterSlashing,
return nil, ErrDataMissing
}

return v.Bellatrix.Message.Body.AttesterSlashings, nil
versionedAttesterSlashings := make([]spec.VersionedAttesterSlashing, len(v.Bellatrix.Message.Body.AttesterSlashings))
for i, attesterSlashing := range v.Bellatrix.Message.Body.AttesterSlashings {
versionedAttesterSlashings[i] = spec.VersionedAttesterSlashing{
Version: spec.DataVersionBellatrix,
Bellatrix: attesterSlashing,
}
}

return versionedAttesterSlashings, nil
case spec.DataVersionCapella:
if v.Capella == nil ||
v.Capella.Message == nil ||
v.Capella.Message.Body == nil {
return nil, ErrDataMissing
}

return v.Capella.Message.Body.AttesterSlashings, nil
versionedAttesterSlashings := make([]spec.VersionedAttesterSlashing, len(v.Capella.Message.Body.AttesterSlashings))
for i, attesterSlashing := range v.Capella.Message.Body.AttesterSlashings {
versionedAttesterSlashings[i] = spec.VersionedAttesterSlashing{
Version: spec.DataVersionCapella,
Capella: attesterSlashing,
}
}

return versionedAttesterSlashings, nil
case spec.DataVersionDeneb:
if v.Deneb == nil ||
v.Deneb.Message == nil ||
v.Deneb.Message.Body == nil {
return nil, ErrDataMissing
}

return v.Deneb.Message.Body.AttesterSlashings, nil
versionedAttesterSlashings := make([]spec.VersionedAttesterSlashing, len(v.Deneb.Message.Body.AttesterSlashings))
for i, attesterSlashing := range v.Deneb.Message.Body.AttesterSlashings {
versionedAttesterSlashings[i] = spec.VersionedAttesterSlashing{
Version: spec.DataVersionDeneb,
Deneb: attesterSlashing,
}
}

return versionedAttesterSlashings, nil
case spec.DataVersionElectra:
if v.Electra == nil ||
v.Electra.Message == nil ||
v.Electra.Message.Body == nil {
return nil, ErrDataMissing
}

return v.Electra.Message.Body.AttesterSlashings, nil
versionedAttesterSlashings := make([]spec.VersionedAttesterSlashing, len(v.Electra.Message.Body.AttesterSlashings))
for i, attesterSlashing := range v.Electra.Message.Body.AttesterSlashings {
versionedAttesterSlashings[i] = spec.VersionedAttesterSlashing{
Version: spec.DataVersionElectra,
Electra: attesterSlashing,
}
}

return versionedAttesterSlashings, nil
default:
return nil, ErrUnsupportedVersion
}
Expand Down
131 changes: 131 additions & 0 deletions spec/electra/aggregateandproof.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// Copyright © 2024 Attestant Limited.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package electra

import (
"bytes"
"encoding/hex"
"encoding/json"
"fmt"
"strconv"
"strings"

"github.com/attestantio/go-eth2-client/spec/phase0"

"github.com/goccy/go-yaml"
"github.com/pkg/errors"
)

// AggregateAndProof is the Ethereum 2 attestation structure.
type AggregateAndProof struct {
AggregatorIndex phase0.ValidatorIndex
Aggregate *Attestation
SelectionProof phase0.BLSSignature `ssz-size:"96"`
}

// aggregateAndProofJSON is the spec representation of the struct.
type aggregateAndProofJSON struct {
AggregatorIndex string `json:"aggregator_index"`
Aggregate *Attestation `json:"aggregate"`
SelectionProof string `json:"selection_proof"`
}

// aggregateAndProofYAML is the spec representation of the struct.
type aggregateAndProofYAML struct {
AggregatorIndex uint64 `yaml:"aggregator_index"`
Aggregate *Attestation `yaml:"aggregate"`
SelectionProof string `yaml:"selection_proof"`
}

// MarshalJSON implements json.Marshaler.
func (a *AggregateAndProof) MarshalJSON() ([]byte, error) {
return json.Marshal(&aggregateAndProofJSON{
AggregatorIndex: fmt.Sprintf("%d", a.AggregatorIndex),
Aggregate: a.Aggregate,
SelectionProof: fmt.Sprintf("%#x", a.SelectionProof),
})
}

// UnmarshalJSON implements json.Unmarshaler.
func (a *AggregateAndProof) UnmarshalJSON(input []byte) error {
var aggregateAndProofJSON aggregateAndProofJSON
if err := json.Unmarshal(input, &aggregateAndProofJSON); err != nil {
return errors.Wrap(err, "invalid JSON")
}

return a.unpack(&aggregateAndProofJSON)
}

func (a *AggregateAndProof) unpack(aggregateAndProofJSON *aggregateAndProofJSON) error {
if aggregateAndProofJSON.AggregatorIndex == "" {
return errors.New("aggregator index missing")
}
aggregatorIndex, err := strconv.ParseUint(aggregateAndProofJSON.AggregatorIndex, 10, 64)
if err != nil {
return errors.Wrap(err, "invalid value for aggregator index")
}
a.AggregatorIndex = phase0.ValidatorIndex(aggregatorIndex)
if aggregateAndProofJSON.Aggregate == nil {
return errors.New("aggregate missing")
}
a.Aggregate = aggregateAndProofJSON.Aggregate
if aggregateAndProofJSON.SelectionProof == "" {
return errors.New("selection proof missing")
}
selectionProof, err := hex.DecodeString(strings.TrimPrefix(aggregateAndProofJSON.SelectionProof, "0x"))
if err != nil {
return errors.Wrap(err, "invalid value for selection proof")
}
if len(selectionProof) != phase0.SignatureLength {
return errors.New("incorrect length for selection proof")
}
copy(a.SelectionProof[:], selectionProof)

return nil
}

// MarshalYAML implements yaml.Marshaler.
func (a *AggregateAndProof) MarshalYAML() ([]byte, error) {
yamlBytes, err := yaml.MarshalWithOptions(&aggregateAndProofYAML{
AggregatorIndex: uint64(a.AggregatorIndex),
Aggregate: a.Aggregate,
SelectionProof: fmt.Sprintf("%#x", a.SelectionProof),
}, yaml.Flow(true))
if err != nil {
return nil, err
}

return bytes.ReplaceAll(yamlBytes, []byte(`"`), []byte(`'`)), nil
}

// UnmarshalYAML implements yaml.Unmarshaler.
func (a *AggregateAndProof) UnmarshalYAML(input []byte) error {
// We unmarshal to the JSON struct to save on duplicate code.
var aggregateAndProofJSON aggregateAndProofJSON
if err := yaml.Unmarshal(input, &aggregateAndProofJSON); err != nil {
return err
}

return a.unpack(&aggregateAndProofJSON)
}

// String returns a string version of the structure.
func (a *AggregateAndProof) String() string {
data, err := yaml.Marshal(a)
if err != nil {
return fmt.Sprintf("ERR: %v", err)
}

return string(data)
}
121 changes: 121 additions & 0 deletions spec/electra/aggregateandproof_ssz.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion spec/electra/attestation.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import (
type Attestation struct {
AggregationBits bitfield.Bitlist `ssz-max:"131072"`
Data *phase0.AttestationData
CommitteeBits bitfield.Bitvector64 `ssz-size:"1"`
CommitteeBits bitfield.Bitvector64 `ssz-size:"8"`
Signature phase0.BLSSignature `ssz-size:"96"`
}

Expand Down
Loading

0 comments on commit 3117883

Please sign in to comment.