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

WiP: Add Malfeasance V2 Handler and Publisher #6184

Closed
wants to merge 28 commits into from
Closed
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
bbcb675
WiP
fasmat Jul 10, 2024
9903b22
Wip
fasmat Jul 25, 2024
5b8a0cf
Merge remote-tracking branch 'origin/develop' into refactor-publisher…
fasmat Jul 26, 2024
4d67bfb
WiP
fasmat Jul 26, 2024
25a6e91
Add malfeasance2 package
fasmat Jul 26, 2024
8444492
Extend handler and add tests
fasmat Jul 26, 2024
023697e
Cleanup
fasmat Jul 26, 2024
3018145
Add new malfeasance database
fasmat Jul 26, 2024
3c74479
Add tests
fasmat Jul 26, 2024
817b0eb
More tests
fasmat Jul 26, 2024
79ff65d
Merge remote-tracking branch 'origin/develop' into refactor-publisher…
fasmat Jul 29, 2024
817a9ab
Merge remote-tracking branch 'origin/develop' into refactor-publisher…
fasmat Jul 30, 2024
f317c5b
Merge remote-tracking branch 'origin/develop' into refactor-publisher…
fasmat Aug 1, 2024
95e4cba
Merge remote-tracking branch 'origin/develop' into refactor-publisher…
fasmat Aug 3, 2024
04e68a1
Merge remote-tracking branch 'origin/develop' into refactor-publisher…
fasmat Aug 5, 2024
ee6ce3b
Merge remote-tracking branch 'origin/develop' into refactor-publisher…
fasmat Aug 6, 2024
0175bc9
Merge remote-tracking branch 'origin/develop' into refactor-publisher…
fasmat Aug 7, 2024
36d48c7
Merge remote-tracking branch 'origin/develop' into refactor-publisher…
fasmat Aug 8, 2024
f87bed5
Merge remote-tracking branch 'origin/develop' into refactor-publisher…
fasmat Aug 12, 2024
42c2e58
Merge remote-tracking branch 'origin/develop' into refactor-publisher…
fasmat Aug 13, 2024
95b48dd
Merge remote-tracking branch 'origin/develop' into refactor-publisher…
fasmat Aug 14, 2024
ce8ef28
Merge remote-tracking branch 'origin/develop' into refactor-publisher…
fasmat Aug 15, 2024
df4ac94
Merge remote-tracking branch 'origin/develop' into refactor-publisher…
fasmat Aug 17, 2024
21490f4
Merge remote-tracking branch 'origin/develop' into refactor-publisher…
fasmat Aug 20, 2024
5018c9b
make generate
fasmat Aug 20, 2024
c179299
Merge remote-tracking branch 'origin/develop' into refactor-publisher…
fasmat Aug 22, 2024
2bfe542
Merge remote-tracking branch 'origin/develop' into refactor-publisher…
fasmat Aug 23, 2024
4bcfcdf
Merge remote-tracking branch 'origin/develop' into refactor-publisher…
fasmat Aug 29, 2024
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: 1 addition & 1 deletion activation/e2e/atx_merge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ func Test_MarryAndMerge(t *testing.T) {

mpub := mocks.NewMockPublisher(ctrl)
mFetch := smocks.NewMockFetcher(ctrl)
mBeacon := activation.NewMockAtxReceiver(ctrl)
mBeacon := activation.NewMockatxReceiver(ctrl)
mTortoise := smocks.NewMockTortoise(ctrl)

tickSize := uint64(3)
Expand Down
2 changes: 1 addition & 1 deletion activation/e2e/builds_atx_v2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ func TestBuilder_SwitchesToBuildV2(t *testing.T) {
edVerifier := signing.NewEdVerifier()
mpub := mocks.NewMockPublisher(ctrl)
mFetch := smocks.NewMockFetcher(ctrl)
mBeacon := activation.NewMockAtxReceiver(ctrl)
mBeacon := activation.NewMockatxReceiver(ctrl)
mTortoise := smocks.NewMockTortoise(ctrl)

atxHdlr := activation.NewHandler(
Expand Down
2 changes: 1 addition & 1 deletion activation/e2e/checkpoint_merged_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func Test_CheckpointAfterMerge(t *testing.T) {

mpub := mocks.NewMockPublisher(ctrl)
mFetch := smocks.NewMockFetcher(ctrl)
mBeacon := activation.NewMockAtxReceiver(ctrl)
mBeacon := activation.NewMockatxReceiver(ctrl)
mTortoise := smocks.NewMockTortoise(ctrl)

atxHdlr := activation.NewHandler(
Expand Down
2 changes: 1 addition & 1 deletion activation/e2e/checkpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ func TestCheckpoint_PublishingSoloATXs(t *testing.T) {
edVerifier := signing.NewEdVerifier()
mpub := mocks.NewMockPublisher(ctrl)
mFetch := smocks.NewMockFetcher(ctrl)
mBeacon := activation.NewMockAtxReceiver(ctrl)
mBeacon := activation.NewMockatxReceiver(ctrl)
mTortoise := smocks.NewMockTortoise(ctrl)

atxHdlr := activation.NewHandler(
Expand Down
2 changes: 1 addition & 1 deletion activation/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func NewHandler(
fetcher system.Fetcher,
goldenATXID types.ATXID,
nipostValidator nipostValidator,
beacon AtxReceiver,
beacon atxReceiver,
tortoise system.Tortoise,
lg *zap.Logger,
opts ...HandlerOption,
Expand Down
4 changes: 2 additions & 2 deletions activation/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ type handlerMocks struct {
mpub *pubsubmocks.MockPublisher
mockFetch *mocks.MockFetcher
mValidator *MocknipostValidator
mbeacon *MockAtxReceiver
mbeacon *MockatxReceiver
mtortoise *mocks.MockTortoise
mMalPublish *MockmalfeasancePublisher
}
Expand Down Expand Up @@ -187,7 +187,7 @@ func newTestHandlerMocks(tb testing.TB, golden types.ATXID) handlerMocks {
mpub: pubsubmocks.NewMockPublisher(ctrl),
mockFetch: mocks.NewMockFetcher(ctrl),
mValidator: NewMocknipostValidator(ctrl),
mbeacon: NewMockAtxReceiver(ctrl),
mbeacon: NewMockatxReceiver(ctrl),
mtortoise: mocks.NewMockTortoise(ctrl),
mMalPublish: NewMockmalfeasancePublisher(ctrl),
}
Expand Down
2 changes: 1 addition & 1 deletion activation/handler_v1.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ type HandlerV1 struct {
tickSize uint64
goldenATXID types.ATXID
nipostValidator nipostValidatorV1
beacon AtxReceiver
beacon atxReceiver
tortoise system.Tortoise
logger *zap.Logger
fetcher system.Fetcher
Expand Down
2 changes: 1 addition & 1 deletion activation/handler_v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ type HandlerV2 struct {
tickSize uint64
goldenATXID types.ATXID
nipostValidator nipostValidatorV2
beacon AtxReceiver
beacon atxReceiver
tortoise system.Tortoise
logger *zap.Logger
fetcher system.Fetcher
Expand Down
2 changes: 1 addition & 1 deletion activation/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (

//go:generate mockgen -typed -package=activation -destination=./mocks.go -source=./interface.go

type AtxReceiver interface {
type atxReceiver interface {
OnAtx(*types.ActivationTx)
}

Expand Down
40 changes: 20 additions & 20 deletions activation/mocks.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion activation/poet.go
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,7 @@ func (c *poetService) Submit(
case err == nil:
return round, nil
case errors.Is(err, ErrUnauthorized):
logger.Warn("failed to submit challenge as unathorized - authorizing again", zap.Error(err))
logger.Warn("failed to submit challenge as unauthorized - authorizing again", zap.Error(err))
auth, err := c.reauthorize(ctx, nodeID, challenge, logger)
if err != nil {
return nil, fmt.Errorf("authorizing: %w", err)
Expand Down
2 changes: 1 addition & 1 deletion checkpoint/recovery_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ func validateAndPreserveData(
mclock := activation.NewMocklayerClock(ctrl)
mfetch := smocks.NewMockFetcher(ctrl)
mvalidator := activation.NewMocknipostValidator(ctrl)
mreceiver := activation.NewMockAtxReceiver(ctrl)
mreceiver := activation.NewMockatxReceiver(ctrl)
mtrtl := smocks.NewMockTortoise(ctrl)
cdb := datastore.NewCachedDB(db, lg)
atxHandler := activation.NewHandler(
Expand Down
4 changes: 2 additions & 2 deletions hare3/hare.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ type nodeclock interface {

func New(
nodeclock nodeclock,
pubsub pubsub.PublishSubsciber,
pubsub pubsub.PublishSubscriber,
db *sql.Database,
atxsdata *atxsdata.Data,
proposals *store.Store,
Expand Down Expand Up @@ -224,7 +224,7 @@ type Hare struct {

// dependencies
nodeclock nodeclock
pubsub pubsub.PublishSubsciber
pubsub pubsub.PublishSubscriber
db *sql.Database
atxsdata *atxsdata.Data
proposals *store.Store
Expand Down
4 changes: 2 additions & 2 deletions hare3/hare_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ type node struct {
proposals *store.Store

ctrl *gomock.Controller
mpublisher *pmocks.MockPublishSubsciber
mpublisher *pmocks.MockPublishSubscriber
msyncer *smocks.MockSyncStateProvider
patrol *layerpatrol.LayerPatrol
tracer *testTracer
Expand Down Expand Up @@ -204,7 +204,7 @@ func (n *node) withOracle() *node {
}

func (n *node) withPublisher() *node {
n.mpublisher = pmocks.NewMockPublishSubsciber(n.ctrl)
n.mpublisher = pmocks.NewMockPublishSubscriber(n.ctrl)
n.mpublisher.EXPECT().Register(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
return n
}
Expand Down
81 changes: 24 additions & 57 deletions malfeasance/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,32 +32,22 @@ var (
type MalfeasanceType byte

const (
// V1 types.
MultipleATXs MalfeasanceType = MalfeasanceType(wire.MultipleATXs)
MultipleBallots = MalfeasanceType(wire.MultipleBallots)
HareEquivocation = MalfeasanceType(wire.HareEquivocation)
InvalidPostIndex = MalfeasanceType(wire.InvalidPostIndex)
InvalidPrevATX = MalfeasanceType(wire.InvalidPrevATX)

// V2 types
// TODO(mafa): for future use.
InvalidActivation MalfeasanceType = iota + 10
InvalidBallot
InvalidHareMsg
DoubleMarry = MalfeasanceType(wire.DoubleMarry)
)

// Handler processes MalfeasanceProof from gossip and, if deems it valid, propagates it to peers.
type Handler struct {
logger *zap.Logger
cdb *datastore.CachedDB

handlersV1 map[MalfeasanceType]HandlerV1
handlersV2 map[MalfeasanceType]HandlerV2

logger *zap.Logger
cdb *datastore.CachedDB
self p2p.Peer
nodeIDs []types.NodeID
tortoise tortoise

handlers map[MalfeasanceType]MalfeasanceHandler
}

func NewHandler(
Expand All @@ -74,17 +64,12 @@ func NewHandler(
nodeIDs: nodeID,
tortoise: tortoise,

handlersV1: make(map[MalfeasanceType]HandlerV1),
handlersV2: make(map[MalfeasanceType]HandlerV2),
handlers: make(map[MalfeasanceType]MalfeasanceHandler),
}
}

func (h *Handler) RegisterHandlerV1(malfeasanceType MalfeasanceType, handler HandlerV1) {
h.handlersV1[malfeasanceType] = handler
}

func (h *Handler) RegisterHandlerV2(malfeasanceType MalfeasanceType, handler HandlerV2) {
h.handlersV2[malfeasanceType] = handler
func (h *Handler) RegisterHandler(malfeasanceType MalfeasanceType, handler MalfeasanceHandler) {
h.handlers[malfeasanceType] = handler
fasmat marked this conversation as resolved.
Show resolved Hide resolved
}

func (h *Handler) reportMalfeasance(smesher types.NodeID, mp *wire.MalfeasanceProof) {
Expand All @@ -96,11 +81,11 @@ func (h *Handler) reportMalfeasance(smesher types.NodeID, mp *wire.MalfeasancePr
}

func (h *Handler) countProof(mp *wire.MalfeasanceProof) {
h.handlersV1[MalfeasanceType(mp.Proof.Type)].ReportProof(numProofs)
h.handlers[MalfeasanceType(mp.Proof.Type)].ReportProof(numProofs)
}

func (h *Handler) countInvalidProof(p *wire.MalfeasanceProof) {
h.handlersV1[MalfeasanceType(p.Proof.Type)].ReportInvalidProof(numInvalidProofs)
h.handlers[MalfeasanceType(p.Proof.Type)].ReportInvalidProof(numInvalidProofs)
}

// HandleSyncedMalfeasanceProof is the sync validator for MalfeasanceProof.
Expand All @@ -116,7 +101,7 @@ func (h *Handler) HandleSyncedMalfeasanceProof(
h.logger.Error("malformed message (sync)", log.ZContext(ctx), zap.Error(err))
return errMalformedData
}
nodeID, err := h.validateAndSave(ctx, &wire.MalfeasanceGossip{MalfeasanceProof: p})
nodeID, err := h.validateAndSave(ctx, &p)
if err == nil && types.Hash32(nodeID) != expHash {
return fmt.Errorf(
"%w: malfeasance proof want %s, got %s",
Expand All @@ -136,51 +121,33 @@ func (h *Handler) HandleMalfeasanceProof(ctx context.Context, peer p2p.Peer, dat
h.logger.Error("malformed message", log.ZContext(ctx), zap.Error(err))
return errMalformedData
}
if peer == h.self {
id, err := h.Validate(ctx, &p)
if err != nil {
h.countInvalidProof(&p.MalfeasanceProof)
return err
}
h.reportMalfeasance(id, &p.MalfeasanceProof)
// node saves malfeasance proof eagerly/atomically with the malicious data.
// it has validated the proof before saving to db.
h.countProof(&p.MalfeasanceProof)
return nil
if p.Eligibility != nil {
return fmt.Errorf("%w: eligibility field was deprecated with hare3", pubsub.ErrValidationReject)
}
_, err := h.validateAndSave(ctx, &p)
_, err := h.validateAndSave(ctx, &p.MalfeasanceProof)
return err
}

func (h *Handler) validateAndSave(ctx context.Context, p *wire.MalfeasanceGossip) (types.NodeID, error) {
if p.Eligibility != nil {
return types.EmptyNodeID, fmt.Errorf(
"%w: eligibility field was deprecated with hare3",
pubsub.ErrValidationReject,
)
}
func (h *Handler) validateAndSave(ctx context.Context, p *wire.MalfeasanceProof) (types.NodeID, error) {
nodeID, err := h.Validate(ctx, p)
switch {
case errors.Is(err, errInvalidProof):
numMalformed.Inc()
return types.EmptyNodeID, err
case err != nil:
h.countInvalidProof(&p.MalfeasanceProof)
h.countInvalidProof(p)
return types.EmptyNodeID, err
}
if err := h.cdb.WithTx(ctx, func(dbtx *sql.Tx) error {
malicious, err := identities.IsMalicious(dbtx, nodeID)
if err != nil {
return fmt.Errorf("check known malicious: %w", err)
} else if malicious {
}
if malicious {
h.logger.Debug("known malicious identity", log.ZContext(ctx), zap.Stringer("smesher", nodeID))
return ErrKnownProof
}
encoded, err := codec.Encode(&p.MalfeasanceProof)
if err != nil {
h.logger.Panic("failed to encode MalfeasanceProof", zap.Error(err))
}
if err := identities.SetMalicious(dbtx, nodeID, encoded, time.Now()); err != nil {
if err := identities.SetMalicious(dbtx, nodeID, codec.MustEncode(p), time.Now()); err != nil {
return fmt.Errorf("add malfeasance proof: %w", err)
}
return nil
Expand All @@ -193,11 +160,11 @@ func (h *Handler) validateAndSave(ctx context.Context, p *wire.MalfeasanceGossip
zap.Error(err),
)
}
return types.EmptyNodeID, err
return nodeID, err
}
h.reportMalfeasance(nodeID, &p.MalfeasanceProof)
h.cdb.CacheMalfeasanceProof(nodeID, &p.MalfeasanceProof)
h.countProof(&p.MalfeasanceProof)
h.reportMalfeasance(nodeID, p)
h.cdb.CacheMalfeasanceProof(nodeID, p)
h.countProof(p)
h.logger.Debug("new malfeasance proof",
log.ZContext(ctx),
zap.Stringer("smesher", nodeID),
Expand All @@ -206,8 +173,8 @@ func (h *Handler) validateAndSave(ctx context.Context, p *wire.MalfeasanceGossip
return nodeID, nil
}

func (h *Handler) Validate(ctx context.Context, p *wire.MalfeasanceGossip) (types.NodeID, error) {
mh, ok := h.handlersV1[MalfeasanceType(p.Proof.Type)]
func (h *Handler) Validate(ctx context.Context, p *wire.MalfeasanceProof) (types.NodeID, error) {
mh, ok := h.handlers[MalfeasanceType(p.Proof.Type)]
if !ok {
return types.EmptyNodeID, fmt.Errorf("%w: unknown malfeasance type", errInvalidProof)
}
Expand Down
Loading
Loading