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

Reject conficting challenge registrations #341

Merged
merged 5 commits into from
Aug 10, 2023
Merged
Show file tree
Hide file tree
Changes from 4 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
2 changes: 2 additions & 0 deletions rpc/rpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ func (r *rpcServer) Submit(ctx context.Context, in *api.SubmitRequest) (*api.Sub
return nil, status.Error(codes.InvalidArgument, err.Error())
case errors.Is(err, service.ErrMaxMembersReached):
return nil, status.Error(codes.ResourceExhausted, err.Error())
case errors.Is(err, service.ErrConflictingRegistration):
return nil, status.Error(codes.AlreadyExists, err.Error())
case err != nil:
logging.FromContext(ctx).Warn("unknown error submitting challenge", zap.Error(err))
return nil, status.Error(codes.Internal, "unknown error submitting challenge")
Expand Down
42 changes: 42 additions & 0 deletions server/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,48 @@ func TestCannotSubmitMoreThanMaxRoundMembers(t *testing.T) {
req.NoError(eg.Wait())
}

// Test if cannot submit two different challenges with the same nodeID.
func TestSubmittingChallengeTwice(t *testing.T) {
t.Parallel()
req := require.New(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

cfg := config.DefaultConfig()
cfg.PoetDir = t.TempDir()
cfg.RawRPCListener = randomHost
cfg.RawRESTListener = randomHost

srv, client := spawnPoet(ctx, t, *cfg)

var eg errgroup.Group
eg.Go(func() error {
poszu marked this conversation as resolved.
Show resolved Hide resolved
return srv.Start(ctx)
})

pubKey, privKey, err := ed25519.GenerateKey(rand.Reader)
req.NoError(err)

submitChallenge := func(ch []byte) error {
_, err = client.Submit(context.Background(), &api.SubmitRequest{
Challenge: ch,
Pubkey: pubKey,
Signature: ed25519.Sign(privKey, ch),
})
return err
}

// Act
req.NoError(submitChallenge([]byte("challenge 1")))
// Submitting the same challenge is OK
req.NoError(submitChallenge([]byte("challenge 1")))
// Submitting a different challenge with the same nodeID is not OK
req.ErrorIs(
submitChallenge([]byte("challenge 2")),
status.Error(codes.AlreadyExists, service.ErrConflictingRegistration.Error()),
)
}

func TestGettingInitialPowParams(t *testing.T) {
t.Parallel()
req := require.New(t)
Expand Down
26 changes: 18 additions & 8 deletions service/round.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package service

import (
"bytes"
"context"
"errors"
"fmt"
Expand Down Expand Up @@ -128,17 +129,26 @@
return ErrMaxMembersReached
}

if has, err := r.challengesDb.Has(key, nil); err != nil {
return err
} else if has {
registered, err := r.challengesDb.Get(key, nil)
switch {
case errors.Is(err, leveldb.ErrNotFound):
// OK - challenge is not registered yet.
case err != nil:
return fmt.Errorf("failed to check if challenge is registered: %w", err)

Check warning on line 137 in service/round.go

View check run for this annotation

Codecov / codecov/patch

service/round.go#L136-L137

Added lines #L136 - L137 were not covered by tests
case bytes.Equal(challenge, registered):
return fmt.Errorf("%w: key: %X", ErrChallengeAlreadySubmitted, key)
default:
return ErrConflictingRegistration
}
err := r.challengesDb.Put(key, challenge, &opt.WriteOptions{Sync: true})
if err == nil {
r.members += 1
r.membersCounter.Inc()

if err := r.challengesDb.Put(key, challenge, &opt.WriteOptions{Sync: true}); err != nil {
return fmt.Errorf("failed to register challenge: %w", err)

Check warning on line 145 in service/round.go

View check run for this annotation

Codecov / codecov/patch

service/round.go#L145

Added line #L145 was not covered by tests
}
return err

r.members += 1
r.membersCounter.Inc()

return nil
}

func (r *round) execute(ctx context.Context, end time.Time, minMemoryLayer, fileWriterBufSize uint) error {
Expand Down
6 changes: 5 additions & 1 deletion service/round_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,14 @@ func TestRound_Submit(t *testing.T) {

// Act
require.NoError(t, round.submit(context.Background(), []byte("key"), challenges[0]))

err = round.submit(context.Background(), []byte("key"), challenges[0])
require.ErrorIs(t, err, ErrChallengeAlreadySubmitted)

err = round.submit(context.Background(), []byte("key"), challenges[1])
require.ErrorIs(t, err, ErrConflictingRegistration)

// Verify
require.ErrorIs(t, err, ErrChallengeAlreadySubmitted)
require.Equal(t, 1, numChallenges(round))
challenge, err := round.challengesDb.Get([]byte("key"), nil)
require.NoError(t, err)
Expand Down
1 change: 1 addition & 0 deletions service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ var (
ErrNotStarted = errors.New("service not started")
ErrAlreadyStarted = errors.New("already started")
ErrChallengeAlreadySubmitted = errors.New("challenge is already submitted")
ErrConflictingRegistration = errors.New("conflicting registration")
ErrRoundNotFinished = errors.New("round is not finished yet")
)

Expand Down