From 825882fead22fbee157dbcade1d6eb33fba0e2ef Mon Sep 17 00:00:00 2001 From: Dhruv Bodani Date: Thu, 29 Sep 2022 17:34:16 +0530 Subject: [PATCH 1/3] add signed and unsigned types for sync duties --- core/signeddata.go | 84 +++++++++++++++++++++++++++++++++++++++ core/signeddata_test.go | 18 +++++++++ core/unsigneddata.go | 22 ++++++++++ core/unsigneddata_test.go | 4 ++ testutil/random.go | 38 ++++++++++++++++++ 5 files changed, 166 insertions(+) diff --git a/core/signeddata.go b/core/signeddata.go index 1b30b592e..50ce904d9 100644 --- a/core/signeddata.go +++ b/core/signeddata.go @@ -805,6 +805,90 @@ func (s *SignedAggregateAndProof) UnmarshalJSON(input []byte) error { return s.SignedAggregateAndProof.UnmarshalJSON(input) } +// SignedSyncMessage wraps altair.SyncCommitteeMessage and implements SignedData. +type SignedSyncMessage struct { + altair.SyncCommitteeMessage +} + +func (s SignedSyncMessage) Signature() Signature { + return SigFromETH2(s.SyncCommitteeMessage.Signature) +} + +func (s SignedSyncMessage) SetSignature(sig Signature) (SignedData, error) { + resp, err := s.clone() + if err != nil { + return nil, err + } + + resp.SyncCommitteeMessage.Signature = sig.ToETH2() + + return resp, nil +} + +func (s SignedSyncMessage) Clone() (SignedData, error) { + return s.clone() +} + +func (s SignedSyncMessage) clone() (SignedSyncMessage, error) { + var resp SignedSyncMessage + err := cloneJSONMarshaler(s, &resp) + if err != nil { + return SignedSyncMessage{}, errors.Wrap(err, "clone signed sync message") + } + + return resp, nil +} + +func (s SignedSyncMessage) MarshalJSON() ([]byte, error) { + return s.SyncCommitteeMessage.MarshalJSON() +} + +func (s *SignedSyncMessage) UnmarshalJSON(input []byte) error { + return s.SyncCommitteeMessage.UnmarshalJSON(input) +} + +// SignedSyncContribution wraps altair.SignedContributionAndProof and implements SignedData. +type SignedSyncContribution struct { + altair.SignedContributionAndProof +} + +func (s SignedSyncContribution) Signature() Signature { + return SigFromETH2(s.SignedContributionAndProof.Signature) +} + +func (s SignedSyncContribution) SetSignature(sig Signature) (SignedData, error) { + resp, err := s.clone() + if err != nil { + return nil, err + } + + resp.SignedContributionAndProof.Signature = sig.ToETH2() + + return resp, err +} + +func (s SignedSyncContribution) Clone() (SignedData, error) { + return s.clone() +} + +func (s SignedSyncContribution) clone() (SignedSyncContribution, error) { + var resp SignedSyncContribution + err := cloneJSONMarshaler(s, &resp) + if err != nil { + return SignedSyncContribution{}, errors.Wrap(err, "clone signed sync contribution") + } + + return resp, nil +} + +func (s SignedSyncContribution) MarshalJSON() ([]byte, error) { + return s.SignedContributionAndProof.MarshalJSON() +} + +func (s *SignedSyncContribution) UnmarshalJSON(input []byte) error { + return s.SignedContributionAndProof.UnmarshalJSON(input) +} + // cloneJSONMarshaler clones the marshaler by serialising to-from json // since eth2 types contain pointers. The result is stored in the value pointed to by v. func cloneJSONMarshaler(data json.Marshaler, v any) error { diff --git a/core/signeddata_test.go b/core/signeddata_test.go index e9dd27eaf..d593ac200 100644 --- a/core/signeddata_test.go +++ b/core/signeddata_test.go @@ -21,6 +21,7 @@ import ( eth2api "github.com/attestantio/go-eth2-client/api" eth2v1 "github.com/attestantio/go-eth2-client/api/v1" "github.com/attestantio/go-eth2-client/spec" + "github.com/attestantio/go-eth2-client/spec/altair" "github.com/attestantio/go-eth2-client/spec/bellatrix" eth2p0 "github.com/attestantio/go-eth2-client/spec/phase0" "github.com/stretchr/testify/require" @@ -86,6 +87,23 @@ func TestSignedDataSetSignature(t *testing.T) { }, }, }, + { + name: "signed sync committee message", + data: core.SignedSyncMessage{ + SyncCommitteeMessage: altair.SyncCommitteeMessage{ + Slot: testutil.RandomSlot(), + BeaconBlockRoot: testutil.RandomRoot(), + ValidatorIndex: testutil.RandomVIdx(), + Signature: testutil.RandomEth2Signature(), + }, + }, + }, + { + name: "signed sync contribution", + data: core.SignedSyncContribution{ + SignedContributionAndProof: testutil.RandomSignedSyncContributionAndProof(), + }, + }, } for _, test := range tests { diff --git a/core/unsigneddata.go b/core/unsigneddata.go index 835775e03..70d216b8a 100644 --- a/core/unsigneddata.go +++ b/core/unsigneddata.go @@ -295,6 +295,28 @@ func (b *VersionedBlindedBeaconBlock) UnmarshalJSON(input []byte) error { return nil } +type SyncContribution struct { + altair.SyncCommitteeContribution +} + +func (s SyncContribution) Clone() (UnsignedData, error) { + var resp SyncContribution + err := cloneJSONMarshaler(s, &resp) + if err != nil { + return nil, errors.Wrap(err, "clone sync contribution") + } + + return resp, err +} + +func (s SyncContribution) MarshalJSON() ([]byte, error) { + return s.SyncCommitteeContribution.MarshalJSON() +} + +func (s *SyncContribution) UnmarshalJSON(input []byte) error { + return s.SyncCommitteeContribution.UnmarshalJSON(input) +} + // UnmarshalUnsignedData returns an instantiated unsigned data based on the duty type. // TODO(corver): Unexport once leadercast is removed or uses protobufs. func UnmarshalUnsignedData(typ DutyType, data []byte) (UnsignedData, error) { diff --git a/core/unsigneddata_test.go b/core/unsigneddata_test.go index 1bcd36e83..10ed5df90 100644 --- a/core/unsigneddata_test.go +++ b/core/unsigneddata_test.go @@ -45,6 +45,10 @@ func TestUnsignedDataClone(t *testing.T) { name: "aggregated attestation", data: core.NewAggregatedAttestation(testutil.RandomAttestation()), }, + { + name: "sync contribution", + data: testutil.RandomCoreSyncContribution(), + }, } for _, test := range tests { diff --git a/testutil/random.go b/testutil/random.go index d1cfea548..2a9232bce 100644 --- a/testutil/random.go +++ b/testutil/random.go @@ -375,6 +375,35 @@ func RandomAggregateAndProof() *eth2p0.AggregateAndProof { } } +func RandomSignedSyncContributionAndProof() altair.SignedContributionAndProof { + return altair.SignedContributionAndProof{ + Message: RandomSyncContributionAndProof(), + Signature: eth2p0.BLSSignature{}, + } +} + +func RandomCoreSyncContribution() core.SyncContribution { + return core.SyncContribution{SyncCommitteeContribution: *RandomSyncCommitteeContribution()} +} + +func RandomSyncContributionAndProof() *altair.ContributionAndProof { + return &altair.ContributionAndProof{ + AggregatorIndex: 0, + Contribution: RandomSyncCommitteeContribution(), + SelectionProof: RandomEth2Signature(), + } +} + +func RandomSyncCommitteeContribution() *altair.SyncCommitteeContribution { + return &altair.SyncCommitteeContribution{ + Slot: RandomSlot(), + BeaconBlockRoot: RandomRoot(), + SubcommitteeIndex: 0, + AggregationBits: RandomBitVec(), + Signature: RandomEth2Signature(), + } +} + func RandomSyncAggregate(t *testing.T) *altair.SyncAggregate { t.Helper() @@ -522,6 +551,15 @@ func RandomBitList() bitfield.Bitlist { return resp } +func RandomBitVec() bitfield.Bitvector128 { + size := 128 + index := rand.Intn(size) + resp := bitfield.NewBitvector128() + resp.SetBitAt(uint64(index), true) + + return resp +} + // RandomSecp256k1Signature returns a random secp256k1 ECDSA signature with the last byte set to 0, 1, 27 or 28. func RandomSecp256k1Signature() []byte { var resp [65]byte From c296910a1f411aed8ca2369f574d5b29cf2e855d Mon Sep 17 00:00:00 2001 From: Dhruv Bodani Date: Fri, 30 Sep 2022 13:26:50 +0530 Subject: [PATCH 2/3] cleanup --- testutil/random.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testutil/random.go b/testutil/random.go index 2a9232bce..1b0fc1e9d 100644 --- a/testutil/random.go +++ b/testutil/random.go @@ -388,7 +388,7 @@ func RandomCoreSyncContribution() core.SyncContribution { func RandomSyncContributionAndProof() *altair.ContributionAndProof { return &altair.ContributionAndProof{ - AggregatorIndex: 0, + AggregatorIndex: RandomVIdx(), Contribution: RandomSyncCommitteeContribution(), SelectionProof: RandomEth2Signature(), } @@ -398,7 +398,7 @@ func RandomSyncCommitteeContribution() *altair.SyncCommitteeContribution { return &altair.SyncCommitteeContribution{ Slot: RandomSlot(), BeaconBlockRoot: RandomRoot(), - SubcommitteeIndex: 0, + SubcommitteeIndex: rand.Uint64(), AggregationBits: RandomBitVec(), Signature: RandomEth2Signature(), } From 56cef5b4ba09cf668f26915a7a81f77cf6ab8a68 Mon Sep 17 00:00:00 2001 From: Dhruv Bodani Date: Fri, 30 Sep 2022 13:33:56 +0530 Subject: [PATCH 3/3] add duty definition --- core/dutydefinition.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/core/dutydefinition.go b/core/dutydefinition.go index de4cecd75..55afa6067 100644 --- a/core/dutydefinition.go +++ b/core/dutydefinition.go @@ -91,3 +91,25 @@ func (EmptyDefinition) Clone() (DutyDefinition, error) { func (EmptyDefinition) MarshalJSON() ([]byte, error) { return nil, nil } + +func NewSyncCommitteDefinition(duty *eth2v1.SyncCommitteeDuty) DutyDefinition { + return SyncCommitteeDefinition{SyncCommitteeDuty: *duty} +} + +type SyncCommitteeDefinition struct { + eth2v1.SyncCommitteeDuty +} + +func (s SyncCommitteeDefinition) Clone() (DutyDefinition, error) { + duty := new(eth2v1.SyncCommitteeDuty) + err := cloneJSONMarshaler(&s.SyncCommitteeDuty, duty) + if err != nil { + return nil, errors.Wrap(err, "clone sync committee definition") + } + + return NewSyncCommitteDefinition(duty), nil +} + +func (s SyncCommitteeDefinition) MarshalJSON() ([]byte, error) { + return s.SyncCommitteeDuty.MarshalJSON() +}