Skip to content

Commit

Permalink
core/bcast: make lighthouse submit attestations idempotent (#813)
Browse files Browse the repository at this point in the history
Catch and ignore lighthouse non-idempotent error. This follows the example set inside goeth2client (but only used for failover in multi-client setup).

category: bug 
ticket: #777
  • Loading branch information
corverroos authored Jul 19, 2022
1 parent fc44c85 commit cdbf821
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 6 deletions.
6 changes: 6 additions & 0 deletions core/bcast/bcast.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package bcast

import (
"context"
"strings"
"time"

eth2client "github.com/attestantio/go-eth2-client"
Expand Down Expand Up @@ -81,6 +82,11 @@ func (b Broadcaster) Broadcast(ctx context.Context, duty core.Duty,
}

err = b.eth2Cl.SubmitAttestations(ctx, []*eth2p0.Attestation{&att.Attestation})
if err != nil && strings.Contains(err.Error(), "PriorAttestationKnown") {
// Lighthouse isn't idempotent, so just swallow this non-issue.
// See reference github.com/attestantio/[email protected]/multi/submitattestations.go:38
err = nil
}
if err == nil {
log.Info(ctx, "Attestation successfully submitted to beacon node",
z.Any("delay", b.delayFunc(duty.Slot)),
Expand Down
21 changes: 15 additions & 6 deletions core/bcast/bcast_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
eth2p0 "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/stretchr/testify/require"

"github.com/obolnetwork/charon/app/errors"
"github.com/obolnetwork/charon/core"
"github.com/obolnetwork/charon/core/bcast"
"github.com/obolnetwork/charon/testutil"
Expand All @@ -31,27 +32,35 @@ import (

func TestBroadcastAttestation(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

mock, err := beaconmock.New()
require.NoError(t, err)

aggData := core.Attestation{Attestation: *testutil.RandomAttestation()}

// Assert output and cancel context
// Assert output and return lighthouse known error on duplicates
var submitted int
mock.SubmitAttestationsFunc = func(ctx context.Context, attestations []*eth2p0.Attestation) error {
require.Len(t, attestations, 1)
require.Equal(t, aggData.Attestation, *attestations[0])
cancel()

return ctx.Err()
submitted++
if submitted > 1 {
// Non-idempotent error returned by lighthouse but swallowed by bcast.
return errors.New("Verification: PriorAttestationKnown")
}

return nil
}

bcaster, err := bcast.New(ctx, mock)
require.NoError(t, err)

err = bcaster.Broadcast(ctx, core.Duty{Type: core.DutyAttester}, "", aggData)
require.ErrorIs(t, err, context.Canceled)

<-ctx.Done()
require.NoError(t, err)
err = bcaster.Broadcast(ctx, core.Duty{Type: core.DutyAttester}, "", aggData)
require.NoError(t, err)
}

func TestBroadcastBeaconBlock(t *testing.T) {
Expand Down

0 comments on commit cdbf821

Please sign in to comment.