Skip to content

Commit

Permalink
core: revert core interfaces (#2682)
Browse files Browse the repository at this point in the history
Revert changes to core interfaces.

This is done since the deneb upgrade no longer requires multiple signatures per signed object. Reverting to the original implementation makes the interfaces simple and code much easier to reason about.

category: refactor
ticket: #2659
  • Loading branch information
xenowits authored Nov 8, 2023
1 parent b45dc65 commit 2593530
Show file tree
Hide file tree
Showing 20 changed files with 254 additions and 638 deletions.
2 changes: 1 addition & 1 deletion cmd/createcluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -1027,6 +1027,6 @@ func builderRegistrationFromETH2(reg core.VersionedSignedValidatorRegistration)
Timestamp: timestamp,
PubKey: pubKey[:],
},
Signature: reg.Signatures()[0],
Signature: reg.Signature(),
}, nil
}
20 changes: 5 additions & 15 deletions core/corepb/v1/core.pb.go

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

1 change: 0 additions & 1 deletion core/corepb/v1/core.proto
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,4 @@ message ParSignedData { // core.ParSignedData
bytes data = 1; // []byte
bytes signature = 2; // core.Signature
int32 share_idx = 3; // int
repeated bytes signatures = 4; // []core.Signature
}
103 changes: 25 additions & 78 deletions core/eth2signeddata.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,9 @@ package core
import (
"context"

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

"github.com/obolnetwork/charon/app/errors"
"github.com/obolnetwork/charon/app/eth2wrap"
"github.com/obolnetwork/charon/app/z"
"github.com/obolnetwork/charon/eth2util"
"github.com/obolnetwork/charon/eth2util/signing"
"github.com/obolnetwork/charon/tbls"
Expand All @@ -30,60 +27,25 @@ var (
_ Eth2SignedData = SyncCommitteeSelection{}
)

// VerifyEth2SignedData verifies signatures associated with the given Eth2SignedData.
// VerifyEth2SignedData verifies signature associated with the given Eth2SignedData.
func VerifyEth2SignedData(ctx context.Context, eth2Cl eth2wrap.Client, data Eth2SignedData, pubkey tbls.PublicKey) error {
epoch, err := data.Epoch(ctx, eth2Cl)
if err != nil {
return err
}

sigs := data.Signatures()
domainNames := data.DomainNames()
msgRoots, err := data.MessageRoots()
sigRoot, err := data.MessageRoot()
if err != nil {
return err
}

if len(domainNames) != len(msgRoots) {
return errors.New("mismatching lengths", z.Int("domain_names", len(domainNames)), z.Int("message_roots", len(msgRoots)))
}
if len(domainNames) != len(sigs) {
return errors.New("mismatching lengths", z.Int("domain_names", len(domainNames)), z.Int("signatures", len(sigs)))
}

for i, sig := range sigs {
err = signing.Verify(ctx, eth2Cl, domainNames[i], epoch, msgRoots[i], sig.ToETH2(), pubkey)
if err != nil {
return errors.Wrap(err, "verify signed data", z.Str("domain", string(domainNames[i])))
}
}

return nil
return signing.Verify(ctx, eth2Cl, data.DomainName(), epoch, sigRoot, data.Signature().ToETH2(), pubkey)
}

// Implement Eth2SignedData for VersionedSignedProposal.

func (p VersionedSignedProposal) DomainNames() []signing.DomainName {
switch p.Version {
case eth2spec.DataVersionPhase0:
return []signing.DomainName{signing.DomainBeaconProposer}
case eth2spec.DataVersionAltair:
return []signing.DomainName{signing.DomainBeaconProposer}
case eth2spec.DataVersionBellatrix:
return []signing.DomainName{signing.DomainBeaconProposer}
case eth2spec.DataVersionCapella:
return []signing.DomainName{signing.DomainBeaconProposer}
case eth2spec.DataVersionDeneb:
var domains []signing.DomainName
domains = append(domains, signing.DomainBeaconProposer) // Deneb beacon block
for range p.Deneb.SignedBlobSidecars {
domains = append(domains, signing.DomainBlobSidecar) // Deneb blob sidecar
}

return domains
default:
return []signing.DomainName{signing.DomainBeaconProposer}
}
func (VersionedSignedProposal) DomainName() signing.DomainName {
return signing.DomainBeaconProposer
}

func (p VersionedSignedProposal) Epoch(ctx context.Context, eth2Cl eth2wrap.Client) (eth2p0.Epoch, error) {
Expand All @@ -97,23 +59,8 @@ func (p VersionedSignedProposal) Epoch(ctx context.Context, eth2Cl eth2wrap.Clie

// Implement Eth2SignedData for VersionedSignedBlindedProposal.

func (p VersionedSignedBlindedProposal) DomainNames() []signing.DomainName {
switch p.Version {
case eth2spec.DataVersionBellatrix:
return []signing.DomainName{signing.DomainBeaconProposer}
case eth2spec.DataVersionCapella:
return []signing.DomainName{signing.DomainBeaconProposer}
case eth2spec.DataVersionDeneb:
var domains []signing.DomainName
domains = append(domains, signing.DomainBeaconProposer) // Deneb beacon block
for range p.Deneb.SignedBlindedBlobSidecars {
domains = append(domains, signing.DomainBlobSidecar) // Deneb blob sidecar
}

return domains
default:
return []signing.DomainName{signing.DomainBeaconProposer}
}
func (VersionedSignedBlindedProposal) DomainName() signing.DomainName {
return signing.DomainBeaconProposer
}

func (p VersionedSignedBlindedProposal) Epoch(ctx context.Context, eth2Cl eth2wrap.Client) (eth2p0.Epoch, error) {
Expand All @@ -127,8 +74,8 @@ func (p VersionedSignedBlindedProposal) Epoch(ctx context.Context, eth2Cl eth2wr

// Implement Eth2SignedData for Attestation.

func (Attestation) DomainNames() []signing.DomainName {
return []signing.DomainName{signing.DomainBeaconAttester}
func (Attestation) DomainName() signing.DomainName {
return signing.DomainBeaconAttester
}

func (a Attestation) Epoch(_ context.Context, _ eth2wrap.Client) (eth2p0.Epoch, error) {
Expand All @@ -137,8 +84,8 @@ func (a Attestation) Epoch(_ context.Context, _ eth2wrap.Client) (eth2p0.Epoch,

// Implement Eth2SignedData for SignedVoluntaryExit.

func (SignedVoluntaryExit) DomainNames() []signing.DomainName {
return []signing.DomainName{signing.DomainExit}
func (SignedVoluntaryExit) DomainName() signing.DomainName {
return signing.DomainExit
}

func (e SignedVoluntaryExit) Epoch(_ context.Context, _ eth2wrap.Client) (eth2p0.Epoch, error) {
Expand All @@ -147,8 +94,8 @@ func (e SignedVoluntaryExit) Epoch(_ context.Context, _ eth2wrap.Client) (eth2p0

// Implement Eth2SignedData for VersionedSignedValidatorRegistration.

func (VersionedSignedValidatorRegistration) DomainNames() []signing.DomainName {
return []signing.DomainName{signing.DomainApplicationBuilder}
func (VersionedSignedValidatorRegistration) DomainName() signing.DomainName {
return signing.DomainApplicationBuilder
}

func (VersionedSignedValidatorRegistration) Epoch(context.Context, eth2wrap.Client) (eth2p0.Epoch, error) {
Expand All @@ -158,8 +105,8 @@ func (VersionedSignedValidatorRegistration) Epoch(context.Context, eth2wrap.Clie

// Implement Eth2SignedData for SignedRandao.

func (SignedRandao) DomainNames() []signing.DomainName {
return []signing.DomainName{signing.DomainRandao}
func (SignedRandao) DomainName() signing.DomainName {
return signing.DomainRandao
}

func (s SignedRandao) Epoch(_ context.Context, _ eth2wrap.Client) (eth2p0.Epoch, error) {
Expand All @@ -168,8 +115,8 @@ func (s SignedRandao) Epoch(_ context.Context, _ eth2wrap.Client) (eth2p0.Epoch,

// Implement Eth2SignedData for BeaconCommitteeSelection.

func (BeaconCommitteeSelection) DomainNames() []signing.DomainName {
return []signing.DomainName{signing.DomainSelectionProof}
func (BeaconCommitteeSelection) DomainName() signing.DomainName {
return signing.DomainSelectionProof
}

func (s BeaconCommitteeSelection) Epoch(ctx context.Context, eth2Cl eth2wrap.Client) (eth2p0.Epoch, error) {
Expand All @@ -178,8 +125,8 @@ func (s BeaconCommitteeSelection) Epoch(ctx context.Context, eth2Cl eth2wrap.Cli

// Implement Eth2SignedData for SignedAggregateAndProof.

func (SignedAggregateAndProof) DomainNames() []signing.DomainName {
return []signing.DomainName{signing.DomainAggregateAndProof}
func (SignedAggregateAndProof) DomainName() signing.DomainName {
return signing.DomainAggregateAndProof
}

func (s SignedAggregateAndProof) Epoch(ctx context.Context, eth2Cl eth2wrap.Client) (eth2p0.Epoch, error) {
Expand All @@ -188,8 +135,8 @@ func (s SignedAggregateAndProof) Epoch(ctx context.Context, eth2Cl eth2wrap.Clie

// Implement Eth2SignedData for SignedSyncMessage.

func (SignedSyncMessage) DomainNames() []signing.DomainName {
return []signing.DomainName{signing.DomainSyncCommittee}
func (SignedSyncMessage) DomainName() signing.DomainName {
return signing.DomainSyncCommittee
}

func (s SignedSyncMessage) Epoch(ctx context.Context, eth2Cl eth2wrap.Client) (eth2p0.Epoch, error) {
Expand All @@ -198,8 +145,8 @@ func (s SignedSyncMessage) Epoch(ctx context.Context, eth2Cl eth2wrap.Client) (e

// Implement Eth2SignedData for SignedSyncContributionAndProof.

func (SignedSyncContributionAndProof) DomainNames() []signing.DomainName {
return []signing.DomainName{signing.DomainContributionAndProof}
func (SignedSyncContributionAndProof) DomainName() signing.DomainName {
return signing.DomainContributionAndProof
}

func (s SignedSyncContributionAndProof) Epoch(ctx context.Context, eth2Cl eth2wrap.Client) (eth2p0.Epoch, error) {
Expand All @@ -208,8 +155,8 @@ func (s SignedSyncContributionAndProof) Epoch(ctx context.Context, eth2Cl eth2wr

// Implement Eth2SignedData for SyncCommitteeSelection.

func (SyncCommitteeSelection) DomainNames() []signing.DomainName {
return []signing.DomainName{signing.DomainSyncCommitteeSelectionProof}
func (SyncCommitteeSelection) DomainName() signing.DomainName {
return signing.DomainSyncCommitteeSelectionProof
}

func (s SyncCommitteeSelection) Epoch(ctx context.Context, eth2Cl eth2wrap.Client) (eth2p0.Epoch, error) {
Expand Down
18 changes: 5 additions & 13 deletions core/eth2signeddata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,30 +92,22 @@ func TestVerifyEth2SignedData(t *testing.T) {
epoch, err := test.data.Epoch(context.Background(), bmock)
require.NoError(t, err)

roots, err := test.data.MessageRoots()
root, err := test.data.MessageRoot()
require.NoError(t, err)

domainNames := test.data.DomainNames()

require.Equal(t, len(roots), len(domainNames))

// Generate private key to sign data
secret, err := tbls.GenerateSecretKey()
require.NoError(t, err)

pubkey, err := tbls.SecretToPublicKey(secret)
require.NoError(t, err)

var sigs []core.Signature
for i := 0; i < len(roots); i++ {
sigData, err := signing.GetDataRoot(context.Background(), bmock, domainNames[i], epoch, roots[i])
require.NoError(t, err)
sigData, err := signing.GetDataRoot(context.Background(), bmock, test.data.DomainName(), epoch, root)
require.NoError(t, err)

sig := sign(t, secret, sigData[:])
sigs = append(sigs, sig)
}
sig := sign(t, secret, sigData[:])

s, err := test.data.SetSignatures(sigs)
s, err := test.data.SetSignature(sig)
require.NoError(t, err)

eth2Signed, ok := s.(core.Eth2SignedData)
Expand Down
4 changes: 2 additions & 2 deletions core/fetcher/fetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ func (f *Fetcher) fetchProposerData(ctx context.Context, slot uint64, defSet cor
return nil, err
}

randao := randaoData.Signatures()[0].ToETH2()
randao := randaoData.Signature().ToETH2()

// TODO(dhruv): replace hardcoded graffiti with the one from cluster-lock.json
var graffiti [32]byte
Expand Down Expand Up @@ -289,7 +289,7 @@ func (f *Fetcher) fetchBuilderProposerData(ctx context.Context, slot uint64, def
return nil, err
}

randao := randaoData.Signatures()[0].ToETH2()
randao := randaoData.Signature().ToETH2()

// TODO(dhruv): replace hardcoded graffiti with the one from cluster-lock.json
var graffiti [32]byte
Expand Down
8 changes: 4 additions & 4 deletions core/fetcher/fetcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,14 +294,14 @@ func TestFetchBlocks(t *testing.T) {
require.NoError(t, err)
require.EqualValues(t, slot, slotA)
require.Equal(t, feeRecipientAddr, fmt.Sprintf("%#x", dutyDataA.Capella.Body.ExecutionPayload.FeeRecipient))
assertRandao(t, randaoByPubKey[pubkeysByIdx[vIdxA]].Signatures()[0].ToETH2(), dutyDataA)
assertRandao(t, randaoByPubKey[pubkeysByIdx[vIdxA]].Signature().ToETH2(), dutyDataA)

dutyDataB := resDataSet[pubkeysByIdx[vIdxB]].(core.VersionedProposal)
slotB, err := dutyDataB.Slot()
require.NoError(t, err)
require.EqualValues(t, slot, slotB)
require.Equal(t, feeRecipientAddr, fmt.Sprintf("%#x", dutyDataB.Capella.Body.ExecutionPayload.FeeRecipient))
assertRandao(t, randaoByPubKey[pubkeysByIdx[vIdxB]].Signatures()[0].ToETH2(), dutyDataB)
assertRandao(t, randaoByPubKey[pubkeysByIdx[vIdxB]].Signature().ToETH2(), dutyDataB)

return nil
})
Expand Down Expand Up @@ -330,14 +330,14 @@ func TestFetchBlocks(t *testing.T) {
require.NoError(t, err)
require.EqualValues(t, slot, slotA)
require.Equal(t, feeRecipientAddr, fmt.Sprintf("%#x", dutyDataA.Capella.Body.ExecutionPayloadHeader.FeeRecipient))
assertRandaoBlindedBlock(t, randaoByPubKey[pubkeysByIdx[vIdxA]].Signatures()[0].ToETH2(), dutyDataA)
assertRandaoBlindedBlock(t, randaoByPubKey[pubkeysByIdx[vIdxA]].Signature().ToETH2(), dutyDataA)

dutyDataB := resDataSet[pubkeysByIdx[vIdxB]].(core.VersionedBlindedProposal)
slotB, err := dutyDataB.Slot()
require.NoError(t, err)
require.EqualValues(t, slot, slotB)
require.Equal(t, feeRecipientAddr, fmt.Sprintf("%#x", dutyDataB.Capella.Body.ExecutionPayloadHeader.FeeRecipient))
assertRandaoBlindedBlock(t, randaoByPubKey[pubkeysByIdx[vIdxB]].Signatures()[0].ToETH2(), dutyDataB)
assertRandaoBlindedBlock(t, randaoByPubKey[pubkeysByIdx[vIdxB]].Signature().ToETH2(), dutyDataB)

return nil
})
Expand Down
4 changes: 2 additions & 2 deletions core/parsigdb/memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,12 +206,12 @@ func getThresholdMatching(typ core.DutyType, sigs []core.ParSignedData, threshol

sigsByMsgRoot := make(map[[32]byte][]core.ParSignedData) // map[Root][]ParSignedData
for _, sig := range sigs {
combinedRoot, err := core.HashMessageRoots(sig.SignedData)
root, err := sig.MessageRoot()
if err != nil {
return nil, false, err
}

sigsByMsgRoot[combinedRoot] = append(sigsByMsgRoot[combinedRoot], sig)
sigsByMsgRoot[root] = append(sigsByMsgRoot[root], sig)
}

// Return true if we have "threshold" number of signatures.
Expand Down
12 changes: 3 additions & 9 deletions core/proto.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,16 +144,10 @@ func ParSignedDataToProto(data ParSignedData) (*pbv1.ParSignedData, error) {
return nil, errors.Wrap(err, "marshal share signed data")
}

var sigs [][]byte
for _, sig := range data.Signatures() {
sigs = append(sigs, sig)
}

return &pbv1.ParSignedData{
Data: d,
Signature: sigs[0], // TODO(xenowits): Remove this when v0.19.0 is released.
Signatures: sigs,
ShareIdx: int32(data.ShareIdx),
Data: d,
Signature: data.Signature(),
ShareIdx: int32(data.ShareIdx),
}, nil
}

Expand Down
4 changes: 2 additions & 2 deletions core/proto_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,9 +195,9 @@ func TestParSignedData(t *testing.T) {
func TestSetSignature(t *testing.T) {
for typ, signedData := range randomSignedData(t) {
t.Run(typ.String(), func(t *testing.T) {
signedData2, err := signedData.SetSignatures([]core.Signature{testutil.RandomCoreSignature()})
signedData2, err := signedData.SetSignature(testutil.RandomCoreSignature())
require.NoError(t, err)
require.NotEqual(t, signedData.Signatures(), signedData2.Signatures()) // Asset original not modified
require.NotEqual(t, signedData.Signature(), signedData2.Signature()) // Asset original not modified
})
}
}
Expand Down
Loading

0 comments on commit 2593530

Please sign in to comment.