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

testutil/validatormock: supporting universal proposal #2928

Merged
merged 1 commit into from
Mar 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions testutil/validatormock/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,10 @@
if err = ProposeBlindedBlock(ctx, eth2Cl, m.signFunc, eth2Slot); err != nil {
return err
}
case core.DutyUniversalProposer:
if err = ProposeUniversalBlock(ctx, eth2Cl, m.signFunc, eth2Slot); err != nil {
return err
}

Check warning on line 293 in testutil/validatormock/component.go

View check run for this annotation

Codecov / codecov/patch

testutil/validatormock/component.go#L290-L293

Added lines #L290 - L293 were not covered by tests
case core.DutyBuilderRegistration:
if !m.builderAPI {
return nil
Expand Down
159 changes: 85 additions & 74 deletions testutil/validatormock/propose.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,17 @@
// SignFunc abstract signing done by the validator client.
type SignFunc func(pubshare eth2p0.BLSPubKey, data []byte) (eth2p0.BLSSignature, error)

// ProposeBlock proposes block for the given slot.
func ProposeBlock(ctx context.Context, eth2Cl eth2wrap.Client, signFunc SignFunc,
func getRandao(ctx context.Context, eth2Cl eth2wrap.Client, signFunc SignFunc,
slot eth2p0.Slot,
) error {
) (eth2p0.BLSSignature, eth2p0.BLSPubKey, eth2p0.Epoch, error) {
valMap, err := eth2Cl.ActiveValidators(ctx)
if err != nil {
return err
return eth2p0.BLSSignature{}, eth2p0.BLSPubKey{}, 0, err

Check warning on line 39 in testutil/validatormock/propose.go

View check run for this annotation

Codecov / codecov/patch

testutil/validatormock/propose.go#L39

Added line #L39 was not covered by tests
}

slotsPerEpoch, err := eth2Cl.SlotsPerEpoch(ctx)
if err != nil {
return err
return eth2p0.BLSSignature{}, eth2p0.BLSPubKey{}, 0, err

Check warning on line 44 in testutil/validatormock/propose.go

View check run for this annotation

Codecov / codecov/patch

testutil/validatormock/propose.go#L44

Added line #L44 was not covered by tests
}
epoch := eth2p0.Epoch(uint64(slot) / slotsPerEpoch)

Expand All @@ -57,7 +56,7 @@
}
eth2Resp, err := eth2Cl.ProposerDuties(ctx, opts)
if err != nil {
return err
return eth2p0.BLSSignature{}, eth2p0.BLSPubKey{}, 0, err

Check warning on line 59 in testutil/validatormock/propose.go

View check run for this annotation

Codecov / codecov/patch

testutil/validatormock/propose.go#L59

Added line #L59 was not covered by tests
}
duties := eth2Resp.Data

Expand All @@ -70,27 +69,83 @@
}

if slotProposer == nil {
return nil
return eth2p0.BLSSignature{}, eth2p0.BLSPubKey{}, 0, nil

Check warning on line 72 in testutil/validatormock/propose.go

View check run for this annotation

Codecov / codecov/patch

testutil/validatormock/propose.go#L72

Added line #L72 was not covered by tests
}

var (
pubkey eth2p0.BLSPubKey
block *eth2api.VersionedProposal
)
pubkey = slotProposer.PubKey

// Create randao reveal to propose block
randaoSigRoot, err := eth2util.SignedEpoch{Epoch: epoch}.HashTreeRoot()
if err != nil {
return err
return eth2p0.BLSSignature{}, eth2p0.BLSPubKey{}, 0, err

Check warning on line 78 in testutil/validatormock/propose.go

View check run for this annotation

Codecov / codecov/patch

testutil/validatormock/propose.go#L78

Added line #L78 was not covered by tests
}

randaoSigData, err := signing.GetDataRoot(ctx, eth2Cl, signing.DomainRandao, epoch, randaoSigRoot)
if err != nil {
return err
return eth2p0.BLSSignature{}, eth2p0.BLSPubKey{}, 0, err

Check warning on line 83 in testutil/validatormock/propose.go

View check run for this annotation

Codecov / codecov/patch

testutil/validatormock/propose.go#L83

Added line #L83 was not covered by tests
}

randao, err := signFunc(slotProposer.PubKey, randaoSigData[:])
if err != nil {
return eth2p0.BLSSignature{}, eth2p0.BLSPubKey{}, 0, err
}

Check warning on line 89 in testutil/validatormock/propose.go

View check run for this annotation

Codecov / codecov/patch

testutil/validatormock/propose.go#L88-L89

Added lines #L88 - L89 were not covered by tests

return randao, slotProposer.PubKey, epoch, nil
}

// ProposeUniversalBlock proposes universal block for the given slot.
func ProposeUniversalBlock(ctx context.Context, eth2Cl eth2wrap.Client, signFunc SignFunc,
slot eth2p0.Slot,
) error {
randao, pubkey, epoch, err := getRandao(ctx, eth2Cl, signFunc, slot)
if err != nil {
return err
}

Check warning on line 101 in testutil/validatormock/propose.go

View check run for this annotation

Codecov / codecov/patch

testutil/validatormock/propose.go#L100-L101

Added lines #L100 - L101 were not covered by tests

// Get Unsigned beacon block with given randao and slot
proposalOpts := &eth2api.UniversalProposalOpts{
Slot: slot,
RandaoReveal: randao,
}
eth2ProposalResp, err := eth2Cl.UniversalProposal(ctx, proposalOpts)
if err != nil {
return errors.Wrap(err, "vmock beacon block proposal")
}

Check warning on line 111 in testutil/validatormock/propose.go

View check run for this annotation

Codecov / codecov/patch

testutil/validatormock/propose.go#L110-L111

Added lines #L110 - L111 were not covered by tests

block := eth2ProposalResp.Data
if block == nil {
return errors.New("block not found")
}

Check warning on line 116 in testutil/validatormock/propose.go

View check run for this annotation

Codecov / codecov/patch

testutil/validatormock/propose.go#L115-L116

Added lines #L115 - L116 were not covered by tests

// Sign beacon block
blockSigRoot, err := block.Root()
if err != nil {
return err
}

Check warning on line 122 in testutil/validatormock/propose.go

View check run for this annotation

Codecov / codecov/patch

testutil/validatormock/propose.go#L121-L122

Added lines #L121 - L122 were not covered by tests

blockSigData, err := signing.GetDataRoot(ctx, eth2Cl, signing.DomainBeaconProposer, epoch, blockSigRoot)
if err != nil {
return err
}

Check warning on line 127 in testutil/validatormock/propose.go

View check run for this annotation

Codecov / codecov/patch

testutil/validatormock/propose.go#L126-L127

Added lines #L126 - L127 were not covered by tests

sig, err := signFunc(pubkey, blockSigData[:])
if err != nil {
return err
}

Check warning on line 132 in testutil/validatormock/propose.go

View check run for this annotation

Codecov / codecov/patch

testutil/validatormock/propose.go#L131-L132

Added lines #L131 - L132 were not covered by tests

if block.Proposal != nil {
return submitVersionedSignedProposal(ctx, sig, eth2Cl, block.Proposal)
}
if block.BlindedProposal != nil {
return submitVersionedSignedBlindedProposal(ctx, sig, eth2Cl, block.BlindedProposal)
}

Check warning on line 139 in testutil/validatormock/propose.go

View check run for this annotation

Codecov / codecov/patch

testutil/validatormock/propose.go#L137-L139

Added lines #L137 - L139 were not covered by tests

return errors.New("invalid block")

Check warning on line 141 in testutil/validatormock/propose.go

View check run for this annotation

Codecov / codecov/patch

testutil/validatormock/propose.go#L141

Added line #L141 was not covered by tests
}

// ProposeBlock proposes block for the given slot.
func ProposeBlock(ctx context.Context, eth2Cl eth2wrap.Client, signFunc SignFunc,
slot eth2p0.Slot,
) error {
randao, pubkey, epoch, err := getRandao(ctx, eth2Cl, signFunc, slot)
if err != nil {
return err
}
Expand All @@ -104,8 +159,8 @@
if err != nil {
return errors.Wrap(err, "vmock beacon block proposal")
}
block = eth2ProposalResp.Data

block := eth2ProposalResp.Data
if block == nil {
return errors.New("block not found")
}
Expand All @@ -126,6 +181,12 @@
return err
}

return submitVersionedSignedProposal(ctx, sig, eth2Cl, block)
}

func submitVersionedSignedProposal(ctx context.Context, sig eth2p0.BLSSignature,
eth2Cl eth2wrap.Client, block *eth2api.VersionedProposal,
) error {
// Create signed beacon block proposal.
signedBlock := new(eth2api.VersionedSignedProposal)
signedBlock.Version = block.Version
Expand Down Expand Up @@ -170,63 +231,7 @@
func ProposeBlindedBlock(ctx context.Context, eth2Cl eth2wrap.Client, signFunc SignFunc,
slot eth2p0.Slot,
) error {
valMap, err := eth2Cl.ActiveValidators(ctx)
if err != nil {
return err
}

slotsPerEpoch, err := eth2Cl.SlotsPerEpoch(ctx)
if err != nil {
return err
}

epoch := eth2p0.Epoch(uint64(slot) / slotsPerEpoch)

var indexes []eth2p0.ValidatorIndex
for index := range valMap {
indexes = append(indexes, index)
}

opts := &eth2api.ProposerDutiesOpts{
Epoch: epoch,
Indices: indexes,
}
eth2Resp, err := eth2Cl.ProposerDuties(ctx, opts)
if err != nil {
return err
}
duties := eth2Resp.Data

var slotProposer *eth2v1.ProposerDuty
for _, duty := range duties {
if duty.Slot == slot {
slotProposer = duty
break
}
}

if slotProposer == nil {
return nil
}

var (
pubkey eth2p0.BLSPubKey
block *eth2api.VersionedBlindedProposal
)
pubkey = slotProposer.PubKey

// Create randao reveal to propose block
randaoSigRoot, err := eth2util.SignedEpoch{Epoch: epoch}.HashTreeRoot()
if err != nil {
return err
}

randaoSigData, err := signing.GetDataRoot(ctx, eth2Cl, signing.DomainRandao, epoch, randaoSigRoot)
if err != nil {
return err
}

randao, err := signFunc(slotProposer.PubKey, randaoSigData[:])
randao, pubkey, epoch, err := getRandao(ctx, eth2Cl, signFunc, slot)
if err != nil {
return err
}
Expand All @@ -240,8 +245,8 @@
if err != nil {
return errors.Wrap(err, "vmock blinded beacon block proposal")
}
block = proposalResp.Data

block := proposalResp.Data
if block == nil {
return errors.New("block not found")
}
Expand All @@ -262,6 +267,12 @@
return err
}

return submitVersionedSignedBlindedProposal(ctx, sig, eth2Cl, block)
}

func submitVersionedSignedBlindedProposal(ctx context.Context, sig eth2p0.BLSSignature,
eth2Cl eth2wrap.Client, block *eth2api.VersionedBlindedProposal,
) error {
// create signed beacon block
signedBlock := new(eth2api.VersionedSignedBlindedProposal)
signedBlock.Version = block.Version
Expand Down
48 changes: 48 additions & 0 deletions testutil/validatormock/propose_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,54 @@ func TestProposeBlindedBlock(t *testing.T) {
require.NoError(t, err)
}

func TestProposeUniversalBlock(t *testing.T) {
ctx := context.Background()

// Configure beacon mock
valSet := beaconmock.ValidatorSetA
beaconMock, err := beaconmock.New(
beaconmock.WithValidatorSet(valSet),
beaconmock.WithDeterministicProposerDuties(0),
)
require.NoError(t, err)

// Signature stub function
signFunc := func(key eth2p0.BLSPubKey, _ []byte) (eth2p0.BLSSignature, error) {
var sig eth2p0.BLSSignature
copy(sig[:], key[:])

return sig, nil
}

slotsPerEpoch, err := beaconMock.SlotsPerEpoch(ctx)
require.NoError(t, err)

block := testutil.RandomPhase0BeaconBlock()
block.Slot = eth2p0.Slot(slotsPerEpoch)

mockVAPI := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
testResponse := []byte(`{"version":"phase0","data":`)
blockJSON, err := block.MarshalJSON()
require.NoError(t, err)

testResponse = append(testResponse, blockJSON...)
testResponse = append(testResponse, []byte(`}`)...)
require.NoError(t, err)

_, _ = w.Write(testResponse)
}))
defer mockVAPI.Close()

provider := addrWrap{
Client: beaconMock,
addr: mockVAPI.URL,
}

// Call propose block function
err = validatormock.ProposeUniversalBlock(ctx, provider, signFunc, eth2p0.Slot(slotsPerEpoch))
require.NoError(t, err)
}

type addrWrap struct {
eth2wrap.Client
addr string
Expand Down
Loading