Skip to content

Commit

Permalink
feat(p2p): Head requests respects SoftFailure during Verify check
Browse files Browse the repository at this point in the history
  • Loading branch information
renaynay committed Sep 20, 2023
1 parent a6544e3 commit 9b2f384
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 6 deletions.
10 changes: 6 additions & 4 deletions headertest/dummy_header.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ type DummyHeader struct {
// VerifyFailure allows for testing scenarios where a header would fail
// verification. When set to true, it forces a failure.
VerifyFailure bool
// SoftFailure allows for testing scenarios where a header would fail
// verification with SoftFailure set to true
SoftFailure bool
}

func RandDummyHeader(t *testing.T) *DummyHeader {
Expand Down Expand Up @@ -96,11 +99,10 @@ func (d *DummyHeader) IsExpired(period time.Duration) bool {
return expirationTime.Before(time.Now())
}

func (d *DummyHeader) Verify(header *DummyHeader) error {
if header.VerifyFailure {
return ErrDummyVerify
func (d *DummyHeader) Verify(hdr *DummyHeader) error {
if hdr.VerifyFailure {
return &header.VerifyError{Reason: ErrDummyVerify, SoftFailure: hdr.SoftFailure}
}

return nil
}

Expand Down
13 changes: 11 additions & 2 deletions p2p/exchange.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package p2p
import (
"bytes"
"context"
"errors"
"fmt"
"math/rand"
"sort"
Expand Down Expand Up @@ -155,12 +156,20 @@ func (ex *Exchange[H]) Head(ctx context.Context, opts ...header.HeadOption[H]) (
if useTrackedPeers {
err = reqParams.TrustedHead.Verify(headers[0])
if err != nil {
log.Errorw("verifying head received from tracked peer", "tracked peer", from,
"height", headers[0].Height(), "err", err)
var verErr *header.VerifyError
if errors.As(err, &verErr) && verErr.SoftFailure {
log.Debugw("received head from tracked peer that soft-failed verification",
"tracked peer", from, "err", err)
headerRespCh <- headers[0]
return
}
// bad head was given, block peer
ex.peerTracker.blockPeer(from, fmt.Errorf("returned bad head: %w", err))
log.Errorw("verifying head received from tracked peer", "tracked peer", from,
"height", headers[0].Height(), "err", err)
headerRespCh <- zero
return

}
}
// request ensures that the result slice will have at least one Header
Expand Down
44 changes: 44 additions & 0 deletions p2p/exchange_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,50 @@ func TestExchange_RequestHead(t *testing.T) {
}
}

// TestExchange_RequestHead_SoftFailure tests that the exchange still processes
// a Head response that has a SoftFailure.
func TestExchange_RequestHead_SoftFailure(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)

hosts := createMocknet(t, 3)
exchg, _ := createP2PExAndServer(t, hosts[0], hosts[1])

// create a tracked peer
suite := headertest.NewTestSuite(t)
trackedStore := headertest.NewStore[*headertest.DummyHeader](t, suite, 50)
// create a header that will SoftFail verification and append it to tracked
// peer's store
hdr := suite.GenDummyHeaders(1)[0]
hdr.VerifyFailure = true
hdr.SoftFailure = true
err := trackedStore.Append(ctx, hdr)
require.NoError(t, err)
// start the tracked peer's server
serverSideEx, err := NewExchangeServer[*headertest.DummyHeader](hosts[2], trackedStore,
WithNetworkID[ServerParameters](networkID),
)
require.NoError(t, err)
err = serverSideEx.Start(ctx)
require.NoError(t, err)
t.Cleanup(func() {
err = serverSideEx.Stop(ctx)
require.NoError(t, err)
})

// get first subjective head from trusted peer to initialize the
// exchange's store
var head header.Header[*headertest.DummyHeader]
head, err = exchg.Head(ctx)
require.NoError(t, err)

// now use that trusted head to request a new head from the exchange
// from the tracked peer
softFailHead, err := exchg.Head(ctx, header.WithTrustedHead(head))
require.NoError(t, err)
assert.Equal(t, trackedStore.HeadHeight, softFailHead.Height())
}

func TestExchange_RequestHead_UnresponsivePeer(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
Expand Down

0 comments on commit 9b2f384

Please sign in to comment.