-
Notifications
You must be signed in to change notification settings - Fork 90
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
dkg/sync: enforce version #1901
Changes from 4 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
// Copyright © 2022-2023 Obol Labs Inc. Licensed under the terms of a Business Source License 1.1 | ||
|
||
package version_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
|
||
"github.com/obolnetwork/charon/app/version" | ||
) | ||
|
||
func TestMinor(t *testing.T) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. also add a case to assert an error from Minor function with error: |
||
minor, err := version.Minor("v0.1.2") | ||
require.NoError(t, err) | ||
require.Equal(t, "v0.1", minor) | ||
|
||
minor, err = version.Minor("1.2.3") | ||
require.NoError(t, err) | ||
require.Equal(t, "1.2", minor) | ||
|
||
minor, err = version.Minor("version 1000.2000.3000") | ||
require.NoError(t, err) | ||
require.Equal(t, "version 1000.2000", minor) | ||
|
||
minor, err = version.Minor("v0.1") | ||
require.NoError(t, err) | ||
require.Equal(t, "v0.1", minor) | ||
|
||
minor, err = version.Minor("v0.1.2.3") | ||
require.NoError(t, err) | ||
require.Equal(t, "v0.1", minor) | ||
|
||
_, err = version.Minor("0") | ||
require.ErrorContains(t, err, "invalid version string") | ||
|
||
_, err = version.Minor("foo") | ||
require.ErrorContains(t, err, "invalid version string") | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ import ( | |
"sync" | ||
"time" | ||
|
||
"github.com/libp2p/go-libp2p/core/crypto" | ||
"github.com/libp2p/go-libp2p/core/host" | ||
"github.com/libp2p/go-libp2p/core/network" | ||
"github.com/libp2p/go-libp2p/core/peer" | ||
|
@@ -25,18 +26,20 @@ import ( | |
) | ||
|
||
const ( | ||
protocolID = "/charon/dkg/sync/1.0.0/" | ||
errInvalidSig = "invalid signature" | ||
protocolID = "/charon/dkg/sync/1.0.0/" | ||
errInvalidSig = "invalid signature" | ||
errInvalidVersion = "invalid version" | ||
) | ||
|
||
// NewServer returns a new Server instance. | ||
func NewServer(tcpNode host.Host, allCount int, defHash []byte) *Server { | ||
func NewServer(tcpNode host.Host, allCount int, defHash []byte, version string) *Server { | ||
return &Server{ | ||
defHash: defHash, | ||
tcpNode: tcpNode, | ||
allCount: allCount, | ||
shutdown: make(map[peer.ID]struct{}), | ||
connected: make(map[peer.ID]struct{}), | ||
version: version, | ||
} | ||
} | ||
|
||
|
@@ -47,6 +50,7 @@ type Server struct { | |
shutdown map[peer.ID]struct{} | ||
connected map[peer.ID]struct{} | ||
defHash []byte | ||
version string | ||
allCount int // Excluding self | ||
tcpNode host.Host | ||
errResponse bool // To return error and exit anywhere in the server flow | ||
|
@@ -73,6 +77,14 @@ func (s *Server) AwaitAllConnected(ctx context.Context) error { | |
} | ||
} | ||
|
||
// setError sets the shared error state for the server. | ||
func (s *Server) setError() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. godoc incorrect |
||
s.mu.Lock() | ||
defer s.mu.Unlock() | ||
|
||
s.errResponse = true | ||
} | ||
|
||
// isError checks if there was any error in between the server flow. | ||
func (s *Server) isError() bool { | ||
s.mu.Lock() | ||
|
@@ -179,20 +191,13 @@ func (s *Server) handleStream(ctx context.Context, stream network.Stream) error | |
SyncTimestamp: msg.Timestamp, | ||
} | ||
|
||
// Verify definition hash | ||
// Note: libp2p verify does another hash of defHash. | ||
ok, err := pubkey.Verify(s.defHash, msg.HashSignature) | ||
var ok bool | ||
resp.Error, ok, err = s.validReq(ctx, pubkey, msg) | ||
if err != nil { | ||
return errors.Wrap(err, "verify sig hash") | ||
return err | ||
} else if !ok { | ||
resp.Error = errInvalidSig | ||
|
||
s.mu.Lock() | ||
s.errResponse = true | ||
s.mu.Unlock() | ||
|
||
log.Error(ctx, "Received mismatching cluster definition hash from peer", nil) | ||
} else if ok && !s.isConnected(pID) { | ||
s.setError() | ||
} else if !s.isConnected(pID) { | ||
count := s.setConnected(pID) | ||
log.Info(ctx, fmt.Sprintf("Connected to peer %d of %d", count, s.allCount)) | ||
} | ||
|
@@ -209,6 +214,29 @@ func (s *Server) handleStream(ctx context.Context, stream network.Stream) error | |
} | ||
} | ||
|
||
// validReq returns an error message and false if the request version or definition hash are invalid. | ||
// Else it returns true or an error. | ||
func (s *Server) validReq(ctx context.Context, pubkey crypto.PubKey, msg *pb.MsgSync) (string, bool, error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we are reading There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. they are immutable fields, no need to lock There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. grouped server fields into immutable and mutable groups |
||
if msg.Version != s.version { | ||
log.Error(ctx, "Received mismatching charon version from peer", nil, | ||
z.Str("expect", s.version), | ||
z.Str("got", msg.Version), | ||
) | ||
|
||
return errInvalidVersion, false, nil | ||
} | ||
|
||
ok, err := pubkey.Verify(s.defHash, msg.HashSignature) | ||
if err != nil { // Note: libp2p verify does another hash of defHash. | ||
return "", false, errors.Wrap(err, "verify sig hash") | ||
} else if !ok { | ||
log.Error(ctx, "Received mismatching cluster definition hash from peer", nil) | ||
return errInvalidSig, false, nil | ||
} | ||
|
||
return "", true, nil | ||
} | ||
|
||
// Start registers sync protocol with the libp2p host. | ||
func (s *Server) Start(ctx context.Context) { | ||
s.tcpNode.SetStreamHandler(protocolID, func(stream network.Stream) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, it supports
v0.1
as input and just returns it.