-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
158 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package misbehavior | ||
|
||
type MisbehaviorService interface { | ||
SafetyFailure(report *SafetyFailureReport) error | ||
// TODO:nm add liveness failures | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package misbehavior | ||
|
||
import ( | ||
"errors" | ||
|
||
"go.uber.org/zap" | ||
) | ||
|
||
// LoggingMisbehaviorService provides an implementation of the MisbehaviorService interface that | ||
// logs misbehavior reports without storing them or forwarding to the network. | ||
type LoggingMisbehaviorService struct { | ||
log *zap.Logger | ||
} | ||
|
||
func NewLoggingMisbehaviorService(log *zap.Logger) *LoggingMisbehaviorService { | ||
return &LoggingMisbehaviorService{ | ||
log: log.Named("misbehavior"), | ||
} | ||
} | ||
|
||
func (m *LoggingMisbehaviorService) SafetyFailure(report *SafetyFailureReport) error { | ||
if report == nil { | ||
return errors.New("report is nil") | ||
} | ||
m.log.Warn( | ||
"misbehavior detected", | ||
zap.String("misbehavior_type", report.misbehaviorType.String()), | ||
zap.Uint32("misbehaving_node_id", report.misbehavingNodeId), | ||
zap.Bool("submitted_by_node", report.submittedByNode), | ||
zap.Any("envelopes", report.envelopes), | ||
) | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package misbehavior | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
"github.com/xmtp/xmtpd/pkg/envelopes" | ||
proto "github.com/xmtp/xmtpd/pkg/proto/xmtpv4/message_api" | ||
testEnvelopes "github.com/xmtp/xmtpd/pkg/testutils/envelopes" | ||
"go.uber.org/zap" | ||
"go.uber.org/zap/zapcore" | ||
"go.uber.org/zap/zaptest/observer" | ||
) | ||
|
||
func TestLoggingMisbehaviorService(t *testing.T) { | ||
env1, err := envelopes.NewOriginatorEnvelope(testEnvelopes.CreateOriginatorEnvelope(t, 1, 1)) | ||
require.NoError(t, err) | ||
env2, err := envelopes.NewOriginatorEnvelope(testEnvelopes.CreateOriginatorEnvelope(t, 1, 2)) | ||
require.NoError(t, err) | ||
|
||
report, err := NewSafetyFailureReport( | ||
1, | ||
proto.Misbehavior_MISBEHAVIOR_DUPLICATE_SEQUENCE_ID, | ||
true, | ||
[]*envelopes.OriginatorEnvelope{env1, env2}, | ||
) | ||
require.NoError(t, err) | ||
|
||
core, observedLogs := observer.New(zapcore.DebugLevel) | ||
logger := zap.New(core) | ||
service := NewLoggingMisbehaviorService(logger) | ||
|
||
err = service.SafetyFailure(report) | ||
require.NoError(t, err) | ||
|
||
logs := observedLogs.All() | ||
require.Len(t, logs, 1) | ||
logEntry := logs[0] | ||
require.Equal(t, "misbehavior detected", logEntry.Message) | ||
require.Equal(t, "MISBEHAVIOR_DUPLICATE_SEQUENCE_ID", logEntry.ContextMap()["misbehavior_type"]) | ||
require.Equal(t, uint32(1), logEntry.ContextMap()["misbehaving_node_id"]) | ||
require.Equal(t, true, logEntry.ContextMap()["submitted_by_node"]) | ||
require.Len(t, logEntry.ContextMap()["envelopes"], 2) | ||
} | ||
|
||
func TestNewSafetyFailureReportValidations(t *testing.T) { | ||
// Test case: No envelopes provided | ||
_, err := NewSafetyFailureReport( | ||
1, | ||
proto.Misbehavior_MISBEHAVIOR_DUPLICATE_SEQUENCE_ID, | ||
true, | ||
nil, | ||
) | ||
require.Error(t, err) | ||
require.Equal(t, "no envelopes provided", err.Error()) | ||
|
||
// Test case: Misbehaving node ID is zero | ||
env, _ := envelopes.NewOriginatorEnvelope(testEnvelopes.CreateOriginatorEnvelope(t, 1, 1)) | ||
_, err = NewSafetyFailureReport( | ||
0, | ||
proto.Misbehavior_MISBEHAVIOR_DUPLICATE_SEQUENCE_ID, | ||
true, | ||
[]*envelopes.OriginatorEnvelope{env}, | ||
) | ||
require.Error(t, err) | ||
require.Equal(t, "misbehaving node id is required", err.Error()) | ||
|
||
// Test case: Misbehavior type is unspecified | ||
_, err = NewSafetyFailureReport( | ||
1, | ||
proto.Misbehavior_MISBEHAVIOR_UNSPECIFIED, | ||
true, | ||
[]*envelopes.OriginatorEnvelope{env}, | ||
) | ||
require.Error(t, err) | ||
require.Equal(t, "misbehavior type is required", err.Error()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package misbehavior | ||
|
||
import ( | ||
"errors" | ||
|
||
"github.com/xmtp/xmtpd/pkg/envelopes" | ||
proto "github.com/xmtp/xmtpd/pkg/proto/xmtpv4/message_api" | ||
) | ||
|
||
type SafetyFailureReport struct { | ||
misbehavingNodeId uint32 | ||
misbehaviorType proto.Misbehavior | ||
submittedByNode bool | ||
envelopes []*envelopes.OriginatorEnvelope | ||
} | ||
|
||
func NewSafetyFailureReport( | ||
misbehavingNodeId uint32, | ||
misbehaviorType proto.Misbehavior, | ||
submittedByNode bool, | ||
envs []*envelopes.OriginatorEnvelope, | ||
) (*SafetyFailureReport, error) { | ||
if len(envs) == 0 { | ||
return nil, errors.New("no envelopes provided") | ||
} | ||
|
||
if misbehavingNodeId == 0 { | ||
return nil, errors.New("misbehaving node id is required") | ||
} | ||
|
||
if misbehaviorType == proto.Misbehavior_MISBEHAVIOR_UNSPECIFIED { | ||
return nil, errors.New("misbehavior type is required") | ||
} | ||
|
||
return &SafetyFailureReport{ | ||
misbehavingNodeId: misbehavingNodeId, | ||
misbehaviorType: misbehaviorType, | ||
submittedByNode: submittedByNode, | ||
envelopes: envs, | ||
}, nil | ||
} |