Skip to content

Commit

Permalink
core: deprecate VersionedSignedBlindedProposal
Browse files Browse the repository at this point in the history
Convert VersionedSignedProposals to their blinded counterpart (requested by go-eth2-client & Beacon API spec) on-demand, so that the execution flow is simpler to understand and debug.
  • Loading branch information
gsora committed Jun 25, 2024
1 parent 551c898 commit 9fdc3a7
Show file tree
Hide file tree
Showing 15 changed files with 135 additions and 523 deletions.
24 changes: 11 additions & 13 deletions core/bcast/bcast.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,26 +74,24 @@ func (b Broadcaster) Broadcast(ctx context.Context, duty core.Duty, set core.Sig
}

var (
block core.VersionedSignedProposal
blindedBlock core.VersionedSignedBlindedProposal

blinded bool
ok bool
block core.VersionedSignedProposal
ok bool
)

block, ok = aggData.(core.VersionedSignedProposal)
if !ok {
// check if it's a blinded proposal
blindedBlock, blinded = aggData.(core.VersionedSignedBlindedProposal)
if !blinded {
return errors.New("invalid proposal")
}
return errors.New("invalid proposal")

Check warning on line 83 in core/bcast/bcast.go

View check run for this annotation

Codecov / codecov/patch

core/bcast/bcast.go#L83

Added line #L83 was not covered by tests
}

switch blinded {
switch block.Blinded {
case true:
blinded, err := block.ToBlinded()
if err != nil {
return errors.Wrap(err, "cannot broadcast, expected blinded proposal")
}

Check warning on line 91 in core/bcast/bcast.go

View check run for this annotation

Codecov / codecov/patch

core/bcast/bcast.go#L88-L91

Added lines #L88 - L91 were not covered by tests

err = b.eth2Cl.SubmitBlindedProposal(ctx, &eth2api.SubmitBlindedProposalOpts{
Proposal: &blindedBlock.VersionedSignedBlindedProposal,
Proposal: &blinded,

Check warning on line 94 in core/bcast/bcast.go

View check run for this annotation

Codecov / codecov/patch

core/bcast/bcast.go#L94

Added line #L94 was not covered by tests
})
default:
err = b.eth2Cl.SubmitProposal(ctx, &eth2api.SubmitProposalOpts{
Expand All @@ -105,7 +103,7 @@ func (b Broadcaster) Broadcast(ctx context.Context, duty core.Duty, set core.Sig
log.Info(ctx, "Successfully submitted block proposal to beacon node",
z.Any("delay", b.delayFunc(duty.Slot)),
z.Any("pubkey", pubkey),
z.Bool("blinded", blinded),
z.Bool("blinded", block.Blinded),
)
}

Expand Down
16 changes: 0 additions & 16 deletions core/eth2signeddata.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ var (
_ Eth2SignedData = VersionedSignedProposal{}
_ Eth2SignedData = Attestation{}
_ Eth2SignedData = SignedVoluntaryExit{}
_ Eth2SignedData = VersionedSignedBlindedProposal{}
_ Eth2SignedData = VersionedSignedValidatorRegistration{}
_ Eth2SignedData = SignedRandao{}
_ Eth2SignedData = BeaconCommitteeSelection{}
Expand Down Expand Up @@ -57,21 +56,6 @@ func (p VersionedSignedProposal) Epoch(ctx context.Context, eth2Cl eth2wrap.Clie
return eth2util.EpochFromSlot(ctx, eth2Cl, slot)
}

// Implement Eth2SignedData for VersionedSignedBlindedProposal.

func (VersionedSignedBlindedProposal) DomainName() signing.DomainName {
return signing.DomainBeaconProposer
}

func (p VersionedSignedBlindedProposal) Epoch(ctx context.Context, eth2Cl eth2wrap.Client) (eth2p0.Epoch, error) {
slot, err := p.VersionedSignedBlindedProposal.Slot()
if err != nil {
return 0, err
}

return eth2util.EpochFromSlot(ctx, eth2Cl, slot)
}

// Implement Eth2SignedData for Attestation.

func (Attestation) DomainName() signing.DomainName {
Expand Down
12 changes: 0 additions & 12 deletions core/eth2signeddata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,6 @@ func TestVerifyEth2SignedData(t *testing.T) {
name: "verify beacon block",
data: testutil.RandomBellatrixCoreVersionedSignedProposal(),
},
{
name: "verify blinded beacon block bellatrix",
data: testutil.RandomBellatrixVersionedSignedBlindedProposal(),
},
{
name: "verify blinded beacon block capella",
data: testutil.RandomCapellaVersionedSignedBlindedProposal(),
},
{
name: "verify blinded beacon block deneb",
data: testutil.RandomDenebVersionedSignedBlindedProposal(),
},
{
name: "verify randao",
data: testutil.RandomCoreSignedRandao(),
Expand Down
10 changes: 6 additions & 4 deletions core/parsigex/parsigex_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,15 +174,17 @@ func TestParSigExVerifier(t *testing.T) {

t.Run("Verify blinded proposal", func(t *testing.T) {
blindedBlock := testutil.RandomDenebVersionedSignedBlindedProposal()
blindedBlock.Deneb.Message.Slot = slot
sigRoot, err := blindedBlock.Root()
blindedBlock.DenebBlinded.Message.Slot = slot
sigRoot, err := blindedBlock.DenebBlinded.Message.HashTreeRoot()
require.NoError(t, err)

sigData, err := signing.GetDataRoot(ctx, bmock, signing.DomainBeaconProposer, epoch, sigRoot)
require.NoError(t, err)

blindedBlock.Deneb.Signature = sign(sigData[:])
data, err := core.NewPartialVersionedSignedBlindedProposal(&blindedBlock.VersionedSignedBlindedProposal, shareIdx)
blindedBlock.DenebBlinded.Signature = sign(sigData[:])
eth2apiBlinded, err := blindedBlock.ToBlinded()
require.NoError(t, err)
data, err := core.NewPartialVersionedSignedBlindedProposal(&eth2apiBlinded, shareIdx)
require.NoError(t, err)

require.NoError(t, verifyFunc(ctx, core.NewProposerDuty(slot), pubkey, data))
Expand Down
1 change: 0 additions & 1 deletion core/serialise_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ var coreTypeFuncs = []func() any{
func() any { return new(core.Attestation) },
func() any { return new(core.Signature) },
func() any { return new(core.SignedVoluntaryExit) },
func() any { return new(core.VersionedSignedBlindedProposal) },

func() any { return new(core.SignedRandao) },
func() any { return new(core.BeaconCommitteeSelection) },
Expand Down
228 changes: 46 additions & 182 deletions core/signeddata.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ var (
_ SignedData = Attestation{}
_ SignedData = Signature{}
_ SignedData = SignedVoluntaryExit{}
_ SignedData = VersionedSignedBlindedProposal{}
_ SignedData = VersionedSignedValidatorRegistration{}
_ SignedData = SignedRandao{}
_ SignedData = BeaconCommitteeSelection{}
Expand All @@ -43,14 +42,12 @@ var (
// Some types support SSZ marshalling and unmarshalling.
_ ssz.Marshaler = VersionedSignedProposal{}
_ ssz.Marshaler = Attestation{}
_ ssz.Marshaler = VersionedSignedBlindedProposal{}
_ ssz.Marshaler = SignedAggregateAndProof{}
_ ssz.Marshaler = SignedSyncMessage{}
_ ssz.Marshaler = SyncContributionAndProof{}
_ ssz.Marshaler = SignedSyncContributionAndProof{}
_ ssz.Unmarshaler = new(VersionedSignedProposal)
_ ssz.Unmarshaler = new(Attestation)
_ ssz.Unmarshaler = new(VersionedSignedBlindedProposal)
_ ssz.Unmarshaler = new(SignedAggregateAndProof)
_ ssz.Unmarshaler = new(SignedSyncMessage)
_ ssz.Unmarshaler = new(SyncContributionAndProof)
Expand Down Expand Up @@ -181,11 +178,57 @@ func NewPartialVersionedSignedProposal(proposal *eth2api.VersionedSignedProposal
}, nil
}

func NewVersionedSignedBlindedProposal(bp *eth2api.VersionedSignedBlindedProposal) (VersionedSignedProposal, error) {
wrap, err := NewVersionedSignedProposal(&eth2api.VersionedSignedProposal{
Version: bp.Version,
Blinded: true,
BellatrixBlinded: bp.Bellatrix,
CapellaBlinded: bp.Capella,
DenebBlinded: bp.Deneb,
})
if err != nil {
return VersionedSignedProposal{}, err
}

Check warning on line 191 in core/signeddata.go

View check run for this annotation

Codecov / codecov/patch

core/signeddata.go#L181-L191

Added lines #L181 - L191 were not covered by tests

return wrap, nil

Check warning on line 193 in core/signeddata.go

View check run for this annotation

Codecov / codecov/patch

core/signeddata.go#L193

Added line #L193 was not covered by tests
}

func NewPartialVersionedSignedBlindedProposal(bp *eth2api.VersionedSignedBlindedProposal, shareIdx int) (ParSignedData, error) {
wrap, err := NewVersionedSignedProposal(&eth2api.VersionedSignedProposal{
Version: bp.Version,
Blinded: true,
BellatrixBlinded: bp.Bellatrix,
CapellaBlinded: bp.Capella,
DenebBlinded: bp.Deneb,
})
if err != nil {
return ParSignedData{}, err
}

Check warning on line 206 in core/signeddata.go

View check run for this annotation

Codecov / codecov/patch

core/signeddata.go#L196-L206

Added lines #L196 - L206 were not covered by tests

return ParSignedData{
SignedData: wrap,
ShareIdx: shareIdx,
}, nil

Check warning on line 211 in core/signeddata.go

View check run for this annotation

Codecov / codecov/patch

core/signeddata.go#L208-L211

Added lines #L208 - L211 were not covered by tests
}

// VersionedSignedProposal is a signed versioned proposal and implements SignedData.
type VersionedSignedProposal struct {
eth2api.VersionedSignedProposal
}

func (p VersionedSignedProposal) ToBlinded() (eth2api.VersionedSignedBlindedProposal, error) {
if !p.Blinded {
return eth2api.VersionedSignedBlindedProposal{}, errors.New("proposal is not blinded")
}

Check warning on line 222 in core/signeddata.go

View check run for this annotation

Codecov / codecov/patch

core/signeddata.go#L219-L222

Added lines #L219 - L222 were not covered by tests

return eth2api.VersionedSignedBlindedProposal{
Version: p.Version,
Bellatrix: p.BellatrixBlinded,
Capella: p.CapellaBlinded,
Deneb: p.DenebBlinded,
}, nil

Check warning on line 229 in core/signeddata.go

View check run for this annotation

Codecov / codecov/patch

core/signeddata.go#L224-L229

Added lines #L224 - L229 were not covered by tests
}

func (p VersionedSignedProposal) Signature() Signature {
switch p.Version {
// No block nil checks since `NewVersionedSignedBeaconBlock` assumed.
Expand Down Expand Up @@ -424,185 +467,6 @@ func (p *VersionedSignedProposal) UnmarshalJSON(input []byte) error {
return nil
}

// NewVersionedSignedBlindedProposal validates and returns a new wrapped VersionedSignedBlindedProposal.
func NewVersionedSignedBlindedProposal(block *eth2api.VersionedSignedBlindedProposal) (VersionedSignedBlindedProposal, error) {
switch block.Version {
case eth2spec.DataVersionBellatrix:
if block.Bellatrix == nil {
return VersionedSignedBlindedProposal{}, errors.New("no bellatrix block")
}
case eth2spec.DataVersionCapella:
if block.Capella == nil {
return VersionedSignedBlindedProposal{}, errors.New("no capella block")
}
case eth2spec.DataVersionDeneb:
if block.Deneb == nil {
return VersionedSignedBlindedProposal{}, errors.New("no deneb block")
}
default:
return VersionedSignedBlindedProposal{}, errors.New("unknown version")
}

return VersionedSignedBlindedProposal{VersionedSignedBlindedProposal: *block}, nil
}

// NewPartialVersionedSignedBlindedProposal is a convenience function that returns a new partial signed proposal.
func NewPartialVersionedSignedBlindedProposal(proposal *eth2api.VersionedSignedBlindedProposal, shareIdx int) (ParSignedData, error) {
wrap, err := NewVersionedSignedBlindedProposal(proposal)
if err != nil {
return ParSignedData{}, err
}

return ParSignedData{
SignedData: wrap,
ShareIdx: shareIdx,
}, nil
}

// VersionedSignedBlindedProposal is a signed versioned blinded proposal and implements SignedData.
type VersionedSignedBlindedProposal struct {
eth2api.VersionedSignedBlindedProposal
}

func (p VersionedSignedBlindedProposal) Signature() Signature {
switch p.Version {
// No block nil checks since `NewVersionedSignedBlindedBeaconBlock` assumed.
case eth2spec.DataVersionBellatrix:
return SigFromETH2(p.Bellatrix.Signature)
case eth2spec.DataVersionCapella:
return SigFromETH2(p.Capella.Signature)
case eth2spec.DataVersionDeneb:
return SigFromETH2(p.Deneb.Signature)
default:
panic("unknown version") // Note this is avoided by using `NewVersionedSignedBlindedProposal`.
}
}

func (p VersionedSignedBlindedProposal) SetSignature(sig Signature) (SignedData, error) {
resp, err := p.clone()
if err != nil {
return nil, err
}

switch resp.Version {
// No block nil checks since `NewVersionedSignedBlindedBeaconBlock` assumed.
case eth2spec.DataVersionBellatrix:
resp.Bellatrix.Signature = sig.ToETH2()
case eth2spec.DataVersionCapella:
resp.Capella.Signature = sig.ToETH2()
case eth2spec.DataVersionDeneb:
resp.Deneb.Signature = sig.ToETH2()
default:
return nil, errors.New("unknown type")
}

return resp, nil
}

func (p VersionedSignedBlindedProposal) MessageRoot() ([32]byte, error) {
switch p.Version {
// No block nil checks since `NewVersionedSignedBlindedBeaconBlock` assumed.
case eth2spec.DataVersionBellatrix:
return p.Bellatrix.Message.HashTreeRoot()
case eth2spec.DataVersionCapella:
return p.Capella.Message.HashTreeRoot()
case eth2spec.DataVersionDeneb:
return p.Deneb.Message.HashTreeRoot()
default:
panic("unknown version") // Note this is avoided by using `NewVersionedSignedBlindedProposal`.
}
}

func (p VersionedSignedBlindedProposal) Clone() (SignedData, error) {
return p.clone()
}

// clone returns a copy of the VersionedSignedBlindedProposal.
// It is similar to Clone that returns the SignedData interface.
func (p VersionedSignedBlindedProposal) clone() (VersionedSignedBlindedProposal, error) {
var resp VersionedSignedBlindedProposal
err := cloneJSONMarshaler(p, &resp)
if err != nil {
return VersionedSignedBlindedProposal{}, errors.Wrap(err, "clone blinded proposal")
}

return resp, nil
}

func (p VersionedSignedBlindedProposal) MarshalJSON() ([]byte, error) {
var marshaller json.Marshaler
switch p.Version {
// No block nil checks since `NewVersionedSignedBlindedProposal` assumed.
case eth2spec.DataVersionBellatrix:
marshaller = p.VersionedSignedBlindedProposal.Bellatrix
case eth2spec.DataVersionCapella:
marshaller = p.VersionedSignedBlindedProposal.Capella
case eth2spec.DataVersionDeneb:
marshaller = p.VersionedSignedBlindedProposal.Deneb
default:
return nil, errors.New("unknown version")
}

block, err := marshaller.MarshalJSON()
if err != nil {
return nil, errors.Wrap(err, "marshal block")
}

version, err := eth2util.DataVersionFromETH2(p.Version)
if err != nil {
return nil, errors.Wrap(err, "convert version")
}

resp, err := json.Marshal(versionedRawBlockJSON{
Version: version,
Block: block,
Blinded: true,
})
if err != nil {
return nil, errors.Wrap(err, "marshal wrapper")
}

return resp, nil
}

func (p *VersionedSignedBlindedProposal) UnmarshalJSON(input []byte) error {
var raw versionedRawBlockJSON
if err := json.Unmarshal(input, &raw); err != nil {
return errors.Wrap(err, "unmarshal block")
}
if !raw.Blinded {
return errors.New("unmarshalled block is not blinded")
}

resp := eth2api.VersionedSignedBlindedProposal{Version: raw.Version.ToETH2()}
switch resp.Version {
case eth2spec.DataVersionBellatrix:
block := new(eth2bellatrix.SignedBlindedBeaconBlock)
if err := json.Unmarshal(raw.Block, &block); err != nil {
return errors.Wrap(err, "unmarshal bellatrix")
}
resp.Bellatrix = block
case eth2spec.DataVersionCapella:
block := new(eth2capella.SignedBlindedBeaconBlock)
if err := json.Unmarshal(raw.Block, &block); err != nil {
return errors.Wrap(err, "unmarshal capella")
}
resp.Capella = block
case eth2spec.DataVersionDeneb:
block := new(eth2deneb.SignedBlindedBeaconBlock)
if err := json.Unmarshal(raw.Block, &block); err != nil {
return errors.Wrap(err, "unmarshal deneb")
}
resp.Deneb = block
default:
return errors.New("unknown version")
}

p.VersionedSignedBlindedProposal = resp

return nil
}

// versionedRawBlockJSON is a custom VersionedSignedBeaconBlock or VersionedSignedBlindedBeaconBlock serialiser.
type versionedRawBlockJSON struct {
Version eth2util.DataVersion `json:"version"`
Expand Down
Loading

0 comments on commit 9fdc3a7

Please sign in to comment.