Skip to content

Commit

Permalink
app: add simnet builder proposer unit test (#858)
Browse files Browse the repository at this point in the history
Add unit test for builder proposer and fix few integration issues.

category: test 
ticket: #809
  • Loading branch information
corverroos authored Jul 26, 2022
1 parent 27915cf commit 2796f78
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 24 deletions.
25 changes: 18 additions & 7 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ func wireCoreWorkflow(ctx context.Context, life *lifecycle.Manager, conf Config,

sender := new(p2p.Sender)

sched, err := scheduler.New(corePubkeys, eth2Cl)
sched, err := scheduler.New(corePubkeys, eth2Cl, conf.BuilderAPI)
if err != nil {
return err
}
Expand Down Expand Up @@ -595,17 +595,21 @@ func wireValidatorMock(conf Config, pubshares []eth2p0.BLSPubKey, sched core.Sch
ctx = log.WithTopic(ctx, "vmock")
go func() {
addr := "http://" + conf.ValidatorAPIAddr
cl, err := eth2http.New(ctx,
eth2Svc, err := eth2http.New(ctx,
eth2http.WithLogLevel(1),
eth2http.WithAddress(addr),
eth2http.WithTimeout(time.Second*10), // Allow sufficient time to block while fetching duties.
)
if err != nil {
log.Warn(ctx, "Cannot connect to validatorapi", err)
log.Error(ctx, "Cannot connect to validatorapi", err)
return
}
eth2Cl, ok := eth2Svc.(validatormock.Eth2Provider)
if !ok {
log.Error(ctx, "Invalid eth2 service", nil)
}

callValidatorMock(ctx, duty, cl, signer, pubshares, addr)
callValidatorMock(ctx, duty, eth2Cl, signer, pubshares, addr)
}()

return nil
Expand All @@ -615,22 +619,29 @@ func wireValidatorMock(conf Config, pubshares []eth2p0.BLSPubKey, sched core.Sch
}

// callValidatorMock calls appropriate validatormock function to attestation and block proposal.
func callValidatorMock(ctx context.Context, duty core.Duty, cl eth2client.Service, signer validatormock.SignFunc, pubshares []eth2p0.BLSPubKey, addr string) {
func callValidatorMock(ctx context.Context, duty core.Duty, eth2Cl validatormock.Eth2Provider, signer validatormock.SignFunc, pubshares []eth2p0.BLSPubKey, addr string) {
switch duty.Type {
case core.DutyAttester:
err := validatormock.Attest(ctx, cl.(*eth2http.Service), signer, eth2p0.Slot(duty.Slot), pubshares...)
err := validatormock.Attest(ctx, eth2Cl, signer, eth2p0.Slot(duty.Slot), pubshares...)
if err != nil {
log.Warn(ctx, "Mock attestation failed", err)
} else {
log.Info(ctx, "Mock attestation submitted to validatorapi", z.I64("slot", duty.Slot))
}
case core.DutyProposer:
err := validatormock.ProposeBlock(ctx, cl.(*eth2http.Service), signer, eth2p0.Slot(duty.Slot), addr, pubshares...)
err := validatormock.ProposeBlock(ctx, eth2Cl, signer, eth2p0.Slot(duty.Slot), addr, pubshares...)
if err != nil {
log.Warn(ctx, "Mock block proposal failed", err)
} else {
log.Info(ctx, "Mock block proposal submitted to validatorapi", z.I64("slot", duty.Slot))
}
case core.DutyBuilderProposer:
err := validatormock.ProposeBlindedBlock(ctx, eth2Cl, signer, eth2p0.Slot(duty.Slot), addr, pubshares...)
if err != nil {
log.Warn(ctx, "Mock blinded block proposal failed", err)
} else {
log.Info(ctx, "Mock blinded block proposal submitted to validatorapi", z.I64("slot", duty.Slot))
}
default:
log.Warn(ctx, "Invalid duty type", nil)
}
Expand Down
11 changes: 10 additions & 1 deletion app/simnet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@ func TestSimnetNoNetwork_WithProposerMockVCs(t *testing.T) {
testSimnet(t, args)
}

func TestSimnetNoNetwork_WithBuilderProposerMockVCs(t *testing.T) {
args := newSimnetArgs(t)
args.BMockOpts = append(args.BMockOpts, beaconmock.WithNoAttesterDuties())
args.BuilderAPI = true
testSimnet(t, args)
}

type simnetArgs struct {
N int
VMocks []bool
Expand All @@ -107,6 +114,7 @@ type simnetArgs struct {
BMockOpts []beaconmock.Option
Lock cluster.Lock
ErrChan chan error
BuilderAPI bool
}

// newSimnetArgs defines the default simnet test args.
Expand Down Expand Up @@ -192,7 +200,8 @@ func testSimnet(t *testing.T, args simnetArgs) {
beaconmock.WithSlotsPerEpoch(1),
}, args.BMockOpts...),
},
P2P: p2p.Config{},
P2P: p2p.Config{},
BuilderAPI: args.BuilderAPI,
}

eg.Go(func() error {
Expand Down
13 changes: 8 additions & 5 deletions core/scheduler/scheduler.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,12 @@ type eth2Provider interface {
type delayFunc func(duty core.Duty, deadline time.Time) <-chan time.Time

// NewForT returns a new scheduler for testing supporting a fake clock.
func NewForT(t *testing.T, clock clockwork.Clock, delayFunc delayFunc, pubkeys []core.PubKey, eth2Svc eth2client.Service) *Scheduler {
func NewForT(t *testing.T, clock clockwork.Clock, delayFunc delayFunc, pubkeys []core.PubKey,
eth2Svc eth2client.Service, builderAPI bool,
) *Scheduler {
t.Helper()

s, err := New(pubkeys, eth2Svc)
s, err := New(pubkeys, eth2Svc, builderAPI)
require.NoError(t, err)

s.clock = clock
Expand All @@ -64,7 +66,7 @@ func NewForT(t *testing.T, clock clockwork.Clock, delayFunc delayFunc, pubkeys [
}

// New returns a new scheduler.
func New(pubkeys []core.PubKey, eth2Svc eth2client.Service) (*Scheduler, error) {
func New(pubkeys []core.PubKey, eth2Svc eth2client.Service, builderAPI bool) (*Scheduler, error) {
eth2Cl, ok := eth2Svc.(eth2Provider)
if !ok {
return nil, errors.New("invalid eth2 client service")
Expand All @@ -80,7 +82,7 @@ func New(pubkeys []core.PubKey, eth2Svc eth2client.Service) (*Scheduler, error)
return time.After(time.Until(deadline))
},
resolvedEpoch: math.MaxUint64,
builderAPI: false,
builderAPI: builderAPI,
}, nil
}

Expand Down Expand Up @@ -150,7 +152,8 @@ func (s *Scheduler) GetDutyDefinition(ctx context.Context, duty core.Duty) (core

defSet, ok := s.getDutyDefinitionSet(duty)
if !ok {
return nil, errors.New("duty not resolved although epoch is marked as resolved")
return nil, errors.New("duty not resolved although epoch is marked as resolved",
z.Any("duty", duty))
}

return defSet.Clone() // Clone before returning.
Expand Down
8 changes: 4 additions & 4 deletions core/scheduler/scheduler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func TestIntegration(t *testing.T) {
"0xb790b322e1cce41c48e3c344cf8d752bdc3cfd51e8eeef44a4bdaac081bc92b53b73e823a9878b5d7a532eb9d9dce1e3",
}

s, err := scheduler.New(pubkeys, eth2Cl)
s, err := scheduler.New(pubkeys, eth2Cl, false)
require.NoError(t, err)

count := 10
Expand Down Expand Up @@ -156,7 +156,7 @@ func TestSchedulerWait(t *testing.T) {
}, err
}

sched := scheduler.NewForT(t, clock, new(delayer).delay, nil, eth2Cl)
sched := scheduler.NewForT(t, clock, new(delayer).delay, nil, eth2Cl, false)
sched.Stop() // Just run wait functions, then quit.
require.NoError(t, sched.Run())
require.EqualValues(t, test.WaitSecs, clock.Since(t0).Seconds())
Expand Down Expand Up @@ -227,7 +227,7 @@ func TestSchedulerDuties(t *testing.T) {
// Construct scheduler
clock := newTestClock(t0)
delayer := new(delayer)
sched := scheduler.NewForT(t, clock, delayer.delay, pubkeys, eth2Cl)
sched := scheduler.NewForT(t, clock, delayer.delay, pubkeys, eth2Cl, false)

// Only test scheduler output for first N slots, so Stop scheduler (and slotTicker) after that.
const stopAfter = 3
Expand Down Expand Up @@ -314,7 +314,7 @@ func TestScheduler_GetDuty(t *testing.T) {

// Construct scheduler
clock := newTestClock(t0)
sched := scheduler.NewForT(t, clock, new(delayer).delay, pubkeys, eth2Cl)
sched := scheduler.NewForT(t, clock, new(delayer).delay, pubkeys, eth2Cl, false)

_, err = sched.GetDutyDefinition(context.Background(), core.Duty{Slot: 0, Type: core.DutyAttester})
// due to current design we will return an error if we request the duty of a slot that has not been resolved
Expand Down
12 changes: 6 additions & 6 deletions core/validatorapi/validatorapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ func (c Component) SubmitAttestations(ctx context.Context, attestations []*eth2p
// BeaconBlockProposal submits the randao for aggregation and inclusion in DutyProposer and then queries the dutyDB for an unsigned beacon block.
func (c Component) BeaconBlockProposal(ctx context.Context, slot eth2p0.Slot, randao eth2p0.BLSSignature, _ []byte) (*spec.VersionedBeaconBlock, error) {
// Get proposer pubkey (this is a blocking query).
pubkey, err := c.getProposerPubkey(ctx, slot)
pubkey, err := c.getProposerPubkey(ctx, core.NewProposerDuty(int64(slot)))
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -367,7 +367,7 @@ func (c Component) SubmitBeaconBlock(ctx context.Context, block *spec.VersionedS
return err
}

pubkey, err := c.getProposerPubkey(ctx, slot)
pubkey, err := c.getProposerPubkey(ctx, core.NewProposerDuty(int64(slot)))
if err != nil {
return err
}
Expand Down Expand Up @@ -402,7 +402,7 @@ func (c Component) SubmitBeaconBlock(ctx context.Context, block *spec.VersionedS
// BlindedBeaconBlockProposal submits the randao for aggregation and inclusion in DutyBuilderProposer and then queries the dutyDB for an unsigned blinded beacon block.
func (c Component) BlindedBeaconBlockProposal(ctx context.Context, slot eth2p0.Slot, randao eth2p0.BLSSignature, _ []byte) (*eth2api.VersionedBlindedBeaconBlock, error) {
// Get proposer pubkey (this is a blocking query).
pubkey, err := c.getProposerPubkey(ctx, slot)
pubkey, err := c.getProposerPubkey(ctx, core.NewBuilderProposerDuty(int64(slot)))
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -465,7 +465,7 @@ func (c Component) SubmitBlindedBeaconBlock(ctx context.Context, block *eth2api.
return err
}

pubkey, err := c.getProposerPubkey(ctx, slot)
pubkey, err := c.getProposerPubkey(ctx, core.NewBuilderProposerDuty(int64(slot)))
if err != nil {
return err
}
Expand Down Expand Up @@ -767,9 +767,9 @@ func (c Component) epochFromSlot(ctx context.Context, slot eth2p0.Slot) (eth2p0.
return eth2p0.Epoch(uint64(slot) / slotsPerEpoch), nil
}

func (c Component) getProposerPubkey(ctx context.Context, slot eth2p0.Slot) (core.PubKey, error) {
func (c Component) getProposerPubkey(ctx context.Context, duty core.Duty) (core.PubKey, error) {
// Get proposer pubkey (this is a blocking query).
defSet, err := c.dutyDefFunc(ctx, core.NewProposerDuty(int64(slot)))
defSet, err := c.dutyDefFunc(ctx, duty)
if err != nil {
return "", err
} else if len(defSet) != 1 {
Expand Down
2 changes: 1 addition & 1 deletion testutil/validatormock/validatormock.go
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ type bellatrixBlindedBeaconBlockProposalJSON struct {
// blindedBeaconBlockProposal is used rather than go-eth2-client's BlindedBeaconBlockProposal to avoid the randao reveal check
// refer: https://github.com/attestantio/go-eth2-client/blob/dceb0b761e5ea6a75534a7b11d544d91a5d610ee/http/blindedbeaconblockproposal.go#L75
func blindedBeaconBlockProposal(_ context.Context, slot eth2p0.Slot, randaoReveal eth2p0.BLSSignature, graffiti []byte, addr string) (*eth2api.VersionedBlindedBeaconBlock, error) {
url := fmt.Sprintf("/eth/v2/validator/blocks/%d?randao_reveal=%#x&graffiti=%#x", slot, randaoReveal, graffiti)
url := fmt.Sprintf("/eth/v1/validator/blinded_blocks/%d?randao_reveal=%#x&graffiti=%#x", slot, randaoReveal, graffiti)
respBodyReader, err := getBlock(url, addr)
if err != nil {
return nil, errors.Wrap(err, "failed to request beacon block proposal")
Expand Down

0 comments on commit 2796f78

Please sign in to comment.